题目描述:
给你一个非负整数数组 nums
,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true
;否则,返回 false
。
示例 1:
ini
输入: nums = [2,3,1,1,4]
输出: true
解释: 可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
ini
输入: nums = [3,2,1,0,4]
输出: false
解释: 无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 105
思路:
吾尝终日而思矣不如须臾之所学也
维护最大可到达的值就好了,每走一步这个值-1,如果当前值更大就替换这个最大到达值就好了
实现:
维护最远能到达的距离,如果发现距离无法增加了,就false。如果距离大于等于数字长度-1,就返回true
Java
class Solution {
public boolean canJump(int[] nums) {
int max = 0; // 最远能到达的距离
int n = nums.length;
if (n==1) return true; // 处理特殊情况 [0]
for (int i = 0; i < n; i++) {
if (nums[i] == 0 && max <= i) { // 当前数字是0了,而且最远就能到这儿了
return false;
}
max = Math.max(max, i+nums[i]); // 当前位置+能跳跃的距离,和已知的最远位置比较一下
if (max >= n-1) { // 到了
return true;
}
}
return false; // 没到过
}
}
这段代码的思路是使用贪心算法,通过维护当前能到达的最远位置(max
)来判断是否能跳到数组末尾。遍历数组时,如果当前位置无法到达(i > max
),则返回false
;如果遇到无法跳跃的0(nums[i] == 0
且max <= i
),也返回false
。每次更新max
,并在能到达末尾时提前返回true
。
优化后的代码实现
java
class Solution {
public boolean canJump(int[] nums) {
int max = 0;
int n = nums.length;
if (n == 1) return true;
for (int i = 0; i < n; i++) {
if (i > max) return false; // 无法到达当前位置
max = Math.max(max, i + nums[i]);
if (max >= n - 1) return true; // 提前到达末尾
if (nums[i] == 0 && max <= i) return false; // 无法跳过当前0
}
return false;
}
}
代码分析
- 提前处理特殊情况 :当数组长度为1时直接返回
true
。 - 维护最大可达位置 :通过
max
记录当前能跳到的最远位置。 - 位置不可达判断 :若当前索引
i
超过max
,说明无法到达,返回false
。 - 提前返回条件 :若
max
已能到达末尾,直接返回true
。 - 处理无法跳跃的0 :当遇到0且无法跳过时,返回
false
。
优化点说明
- 减少无效遍历 :通过
i > max
判断提前终止循环,避免处理无法到达的位置。 - 保留原条件判断:遇到无法跳跃的0时提前返回,减少不必要的迭代。
- 逻辑更严谨 :修正了原代码中未处理
i > max
的漏洞,确保所有位置可达性正确判断。
该方法时间复杂度为O(n),空间复杂度为O(1),兼顾效率和正确性。