45. 跳跃游戏 II
LeetCode 45. 跳跃游戏 II(Jump Game II) 的经典贪心解法,时间复杂度 O(n),空间 O(1),是面试中的高频最优解。
📌 题目简述
给定一个非负整数数组 nums,你初始在下标 0。
nums[i] 表示在位置 i 最多能跳 nums[i] 步。
保证能到达最后位置 ,求最少跳跃次数。
来源:LeetCode 45. Jump Game II(Medium,贪心/广度优先思想)
🔍 核心思路:按"层"跳跃(BFS 思想的贪心实现)
💡 把跳跃过程看作 BFS 的层序遍历:
- 第 0 次跳:只能在
[0, 0]- 第 1 次跳:能到达
[1, nums[0]]- 第 2 次跳:能到达
[nums[0]+1, max(i+nums[i]) for i in 上一层]我们不需要知道具体路径,只需知道每跳一次,最远能到哪。
于是引入两个关键变量:
cur_right:当前这一跳能到达的最右边界next_right:下一跳能到达的最右边界(在遍历当前层时不断更新)
当 i 到达 cur_right,说明必须再跳一次,才能继续前进。
💻 代码逐行解析
python
ans = 0 # 跳跃次数
cur_right = 0 # 当前跳跃能到达的最右位置
next_right = 0 # 下一跳能到达的最远位置
for i in range(len(nums) - 1): # 不需要处理最后一个位置(已到达)
next_right = max(next_right, i + nums[i]) # 更新下一跳的最远边界
if i == cur_right: # 到达当前跳的边界 → 必须跳了!
cur_right = next_right # 更新为下一跳的最远位置
ans += 1 # 跳跃次数 +1
return ans
✅ 为什么
range(len(nums)-1)?因为题目保证能到达终点,一旦
cur_right >= n-1就结束了 。在
i = n-1时已经到达终点,无需再跳,所以提前终止循环更安全(避免无效更新)。
⚠️ 关键细节 & 常见误区
| 误区 | 正确理解 |
|---|---|
| "每次遇到能跳得更远的点就跳" | ❌ 贪心不是"看到更远就跳",而是"走到当前层尽头才跳" |
循环包含 i = n-1 |
❌ 可能导致多算一次跳跃(虽然本题数据不会,但习惯要好) |
初始化 cur_right = nums[0] |
❌ 应从 0 开始,第 0 次跳的位置就是 0 |
📈 复杂度分析
- 时间复杂度:O(n) ------ 一次遍历
- 空间复杂度:O(1) ------ 仅用三个变量
🎯 面试表达话术(简洁有力)
"我用贪心模拟 BFS 的层序遍历。
维护两个变量:
cur_right是当前跳能到的最远位置,next_right是下一跳能到的最远位置。遍历时不断更新
next_right,当走到cur_right时,说明必须跳一次,于是把cur_right更新为next_right,计数加一。这样就能在 O(n) 时间内求出最小跳跃次数。"
🔗 同类题型
- LeetCode 55. 跳跃游戏 :判断是否能到达终点 → 只需维护
max_reach - LeetCode 1306. 跳跃游戏 III:带图遍历 → 用 BFS/DFS
- LeetCode 1345. 跳跃游戏 IV:含相同值跳跃 → 用 BFS + 哈希优化
✅ 总结
这段代码的精妙之处在于:
- 用 O(1) 空间 模拟了 BFS 的层级扩展
- 不关心具体跳哪一步,只关心"最远能到哪"
- 在边界处才决策跳跃,避免过早或过晚
这是贪心算法中"延迟决策 + 边界触发"的经典范式。
如果你想,我可以对比这道题与 BFS 实现版本 的差异,或者带你用同样思路解决 LeetCode 55(跳跃游戏 I)。需要吗?