LeetCode 45. 跳跃游戏 II
本节目标
将连续可达位置看成一层,在层边界耗尽时增加一次跳跃。
这是单序列扫描与边界中“可达性”到“最少次数”的升级。题目保证终点可达,因此可以把一次跳跃能到达的连续区间看作 BFS 的一层。
题意与约束
从下标 0 出发,每次最多跳 nums[i] 步,求到达最后一个下标的最少跳跃次数。
直接思路与瓶颈
逐个落点 BFS 可以求最短路,但每个位置会枚举一段后缀,最坏接近 O(n^2)。相同跳数到达的多个位置可合并成一个连续边界。
贪心模型与算法推导
boundary 是当前跳数能覆盖的最远位置,farthest 是扫描本层位置后下一跳能覆盖的最远位置。扫描到 boundary 时,本层选择已全部比较,必须增加一次跳跃并把 boundary=farthest。最后一个下标不必继续扩展。
正确性依据
在扫描当前层 [previousBoundary,boundary] 时,所有这些位置都恰好可用当前跳数到达。任何再少一跳的路径不可能越过旧边界;farthest 收集该层全部位置的下一跳最大覆盖范围,所以进入下一层后仍保留所有最优选择。每层只加一次跳,首次覆盖终点的层数最小。
样例执行过程
[2,3,1,1,4]:初始层只含 0,其下一层边界为 2,跳数变 1;扫描 1,2 时最大可达为 4,到 i=2 进入第二层,跳数变 2,已覆盖终点。[0] 不进入循环,直接返回 0。
代码实现
- C++
- Python
C++17
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
int jump(vector<int> nums) {
int jumps = 0;
int boundary = 0;
int farthest = 0;
for (int index = 0; index + 1 < static_cast<int>(nums.size()); ++index) {
farthest = max(farthest, index + nums[index]);
if (index == boundary) {
++jumps;
boundary = farthest;
}
}
return jumps;
}
};
Python 3
class Solution:
def jump(self, nums: list[int]) -> int:
jumps = 0
boundary = 0
farthest = 0
for index in range(len(nums) - 1):
farthest = max(farthest, index + nums[index])
if index == boundary:
jumps += 1
boundary = farthest
return jumps
复杂度分析
每个位置至多扫描一次,时间 O(n),额外空间 O(1)。
边界与易错点
- 在更新
farthest后判断是否抵达层边界。 - 循环只到倒数第二个位置,终点无需再触发一次跳跃。
- 本题保证可达;若不保证,应先处理无法越过当前边界的情况。
模式迁移
当一次操作能覆盖一个连续区间时,常可用“当前层边界 + 下一层最远边界”代替显式 BFS,例如最少区间覆盖和最少视频拼接。