给定一个长度为 n
的 0 索引整数数组 nums
。初始位置为 nums[0]
。
每个元素 nums[i]
表示从索引 i
向前跳转的最大长度。换句话说,如果你在 nums[i]
处,你可以跳转到任意 nums[i + j]
处:
0 <= j <= nums[i]
i + j < n
返回到达 nums[n - 1]
的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]
。
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
if (n <= 1) return 0; // 如果数组长度小于等于1,不需要跳跃
int jumps = 0; // 跳跃次数
int current_end = 0; // 当前能到达的最远位置
int farthest = 0; // 记录能达到的最远位置
for (int i = 0; i < n - 1; ++i) { // 只需遍历到倒数第二个元素
farthest = max(farthest, i + nums[i]); // 更新最远位置
if (i == current_end) { // 当到达当前可跳跃的边界时
jumps++; // 需要跳跃
current_end = farthest; // 更新可跳跃的边界
if (current_end >= n - 1) break; // 如果已到达或超出最后一个位置,结束
}
}
return jumps; // 返回跳跃次数
}
};
int main() {
Solution sol;
vector<int> nums = {2, 3, 1, 1, 4}; // 示例输入
cout << "最小跳跃次数: " << sol.jump(nums) << endl; // 输出结果
return 0;
}
代码解释
-
特殊情况处理:
- 如果数组长度小于或等于1,直接返回0,因为不需要跳跃。
-
循环遍历:
for
循环遍历数组,直到倒数第二个元素(因为最后一个元素不需要跳跃到达)。- 在循环中,更新
farthest
,表示当前索引能跳跃到的最远位置。
-
跳跃计数:
- 当当前索引
i
达到current_end
时,增加跳跃计数jumps
,并更新current_end
为farthest
。 - 如果在跳跃过程中更新
current_end
超过了数组的最后一个索引,提前结束循环。
- 当当前索引
复杂度分析
- 时间复杂度:O(n),我们只需遍历一次数组。
- 空间复杂度:O(1),只使用常数级的额外空间。
逻辑分析
1. 问题描述
- 我们有一个数组
nums
,数组中的每个元素表示从当前索引位置最多可以跳跃的距离。 - 我们需要从数组的第一个元素开始,通过最少的跳跃次数,跳到最后一个元素。
2. 贪心策略
贪心的基本思想是:在每次跳跃时,选择能到达的最远位置。我们通过在每一步中选择当前能跳跃的最远位置,贪心地确保每次跳跃的步骤尽量大,从而减少跳跃次数。
3. 核心变量
jumps
:记录跳跃的次数。current_end
:表示当前跳跃范围的终点。在到达current_end
时,必须进行一次跳跃。farthest
:表示在当前跳跃范围内能到达的最远位置。每次更新时,通过farthest = max(farthest, i + nums[i])
来动态计算新的最远位置。
4. 贪心算法的执行逻辑
-
初始化:
jumps = 0
:表示还未跳跃。current_end = 0
:当前跳跃范围的终点为起始位置。farthest = 0
:当前能跳跃到的最远位置也是起始位置。
-
遍历数组:
- 遍历数组时,对于每个索引
i
,更新最远可到达的位置farthest
,farthest = max(farthest, i + nums[i])
,即在当前索引i
,计算从这个位置跳跃后,能到达的最远位置i + nums[i]
。
- 遍历数组时,对于每个索引
-
跳跃判断:
- 如果
i
达到了current_end
(即跳跃的终点),说明在这之前的所有位置都已经处理过了,必须进行一次跳跃,并更新跳跃范围为farthest
。即:到达当前跳跃范围时,必须进行一次跳跃。 - 每次跳跃后,
current_end
更新为farthest
,表示下一次跳跃时的范围边界。
- 如果
-
提前结束:
- 当
farthest
能够到达或超过数组的最后一个元素时,可以提前结束,因为我们已经找到了到达最后一个位置的路径。
- 当
5. 流程示例
假设数组为 nums = [2, 3, 1, 1, 4]
:
-
初始状态:
left = 0, right = n-1
(为了指代开头和结尾)。current_end = 0, farthest = 0, jumps = 0
。
-
第一步:
- 开始遍历:
- i = 0,
farthest = max(farthest, 0 + nums[0]) = max(0, 2) = 2
。 - 到达
current_end
时,必须跳跃,跳跃次数 +1,current_end
更新为farthest = 2
。
- i = 0,
- 开始遍历:
-
第二步:
- 继续遍历:
- i = 1,
farthest = max(farthest, 1 + nums[1]) = max(2, 4) = 4
。 - i = 2,
farthest = max(farthest, 2 + nums[2]) = max(4, 3) = 4
。 - 到达
current_end
时(即 i = 2),再次跳跃,跳跃次数 +1,current_end
更新为farthest = 4
。
- i = 1,
- 继续遍历:
-
结束:
- 因为此时
farthest = 4
,已经可以到达数组的最后一个元素,结束跳跃,返回跳跃次数 2。
- 因为此时