LeetCode 45. 跳跃游戏 II的 Java 实现,核心思路是使用贪心算法。
算法思路
这道题要求到达数组末尾的最小跳跃次数。贪心算法的核心思想是:在每一步的跳跃范围内,选择能跳到的最远位置作为下一步的边界,从而最小化跳跃次数。
具体步骤:
- 维护三个关键变量:
- jumps:记录当前的跳跃次数。
- currentEnd:当前跳跃步数能到达的最远边界。
- farthest:在当前跳跃范围内,所有点能跳到的最远位置。
- 遍历数组(注意:遍历到 n - 2 即可,因为到达最后一个元素后无需再跳跃)。
- 在遍历过程中,不断更新 farthest。
- 当遍历到当前边界 currentEnd 时,说明当前跳跃步数已用完,必须进行一次新的跳跃:
- 跳跃次数 jumps 加 1。
- 将边界 currentEnd 更新为 farthest。
Java 代码实现
class Solution {
public int jump(int[] nums) {
int n = nums.length;
// 如果数组长度小于等于1,说明已经在终点,不需要跳跃
if (n <= 1) {
return 0;
}
int jumps = 0; // 记录跳跃次数 int currentEnd = 0; // 当前跳跃能到达的最远边界 int farthest = 0; // 在当前跳跃范围内,下一步能到达的最远位置 // 遍历数组(除了最后一个元素,因为到达终点后无需再跳) for (int i = 0; i < n - 1; i++) { // 更新在当前跳跃范围内能跳到的最远位置 farthest = Math.max(farthest, i + nums[i]); // 如果到达了当前跳跃的边界,说明必须进行一次新的跳跃 if (i == currentEnd) { jumps++; // 跳跃次数加 1 currentEnd = farthest; // 更新下一次跳跃的边界 } } return jumps; }}
复杂度分析
维度 复杂度 说明
时间复杂度 O(n) 只需对数组进行一次线性遍历
空间复杂度 O(1) 仅使用了常数级别的额外空间
关键细节与易错点
- 循环边界:
循环条件必须是 i < n - 1。因为题目保证可以到达终点,当我们在倒数第二个位置(或更早)更新了 currentEnd 且 currentEnd >= n - 1 时,已经可以到达终点,无需再对最后一个元素进行遍历。 - 跳跃时机:
并不是每走一步都要跳跃,而是只有在到达当前跳跃边界 currentEnd 时,才消耗一次跳跃次数并更新边界。 - 为什么不使用动态规划?
虽然这道题可以使用动态规划(时间复杂度为 O(n^2))求解,但在处理大规模输入时会遇到性能瓶颈。贪心算法将时间复杂度降到了最优的 O(n),是这道题的最佳解法。
需要我顺带把这道题的 Rust 或 Go 版本也写出来吗?