题目描述
nums[i] 是从 i 最多能跳的步数,求从 0 跳到末尾的最少跳跃次数。
思路解析
设 dp[i] 为跳到 i 的最少次数,每格都回看前面所有能跳到它的格子取最小——两重循环 O(n²)。其实不必逐格记账,一遍贪心就够。
转折:当前这一跳能覆盖一段范围 [.. curEnd],就像 BFS 的一层。在这一层里逐格走时,不断用 farthest = max(farthest, i + nums[i]) 记下「下一跳最远能摸到哪」。一旦走到 curEnd(这一层探完了),就必须再跳一次:jumps += 1 并把 curEnd 推到 farthest(进入下一层)。为什么贪心对:同一层里的格子都用一跳可达,下一层的最远边界就是它们能摸到的最远点。
i=0 · 探最远:第一层范围只有 [0,0]。在 0 处算出下一跳最远能到 0+2=2,记下 farthest=2。jumps 仍是 0。
i=0 · 撞到边界:i 正好等于当前边界 curEnd=0,这一层探完了,必须跳一次:jumps=1,新边界 curEnd 推到 farthest=2。橙色范围扩到 [0,2],这是第一跳能覆盖的一层。
i=1 · 探最远:在第一跳范围 [0,2] 内走到 1,它能蹦到 1+3=4,刷新 farthest=4。i=1 还没到边界 curEnd=2,先不加跳数,继续探。
i=2 · 探最远:走到 2,它只能到 2+1=3,没超过现有的 4,farthest 不变。但 i=2 已经撞到 curEnd=2——这一层(第一跳的覆盖范围)探完了。
i=2 · 撞到边界:i 触到边界 curEnd=2,必须再跳一次:jumps=2,新边界 curEnd 推到 farthest=4。注意这一跳的「最远潜力」是从前面 1 号位探出来的——这正是贪心的价值。
i=3 · 探最远:走到 3,它能到 3+1=4,没超过现有 farthest=4。i=3 还没到边界 curEnd=4,不加跳数。这也是循环的倒数第二格。
curEnd 已盖住末尾:边界 curEnd=4 已经盖住终点。循环只走到倒数第二格(i=3)就停,不会在末尾误加跳数。
完成:路径 0 → 1 → 4,最少跳跃次数 = 2。全程一遍扫描,没有回头。
不纠结具体跳到哪一格,只盯「这一层范围里能把下次边界推多远」——这是区间贪心,本质就是隐式的 BFS 分层。
参考代码(Python)
1jumps, curEnd, farthest = 0, 0, 0
2for i in range(len(nums) - 1): # 只到倒数第二格
3 farthest = max(farthest, i + nums[i]) # 探这一层的最远
4 if i == curEnd: # 撞到这一跳的边界
5 jumps += 1 # 必须再跳一次
6 curEnd = farthest # 边界推到最远
7return jumps复杂度分析
- 时间复杂度:O(n) —— 只扫一遍,每格做常数次更新与比较
- 空间复杂度:O(1) —— 只用 jumps / curEnd / farthest 三个变量
套路模板
记住骨架:farthest 持续更新、i 撞到 curEnd 就 cnt+1 并把 curEnd 推到 farthest。最少跳数、覆盖区间、视频拼接都是这套。
1cnt, curEnd, farthest = 0, 0, 0
2for i in range(n - 1):
3 farthest = max(farthest, i + reach(i))
4 if i == curEnd: # 到边界,必须推进一层
5 cnt += 1; curEnd = farthest
6return cnt易错点
- 错误写法:在 i==curEnd 之前就 jumps++ → 正确写法:只有 i==curEnd 才 jumps++(没探完这一层就跳,会把同一层拆成好几跳、多算次数;像 [2,3,1,1,4] 会错算成 3 跳)
- 错误写法:循环跑到最后一格 n-1 → 正确写法:只到 n-2(若末尾恰好 i==curEnd 会再多加一跳,答案多 1)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。