
显然当数组中元素都为正数时,是必然能到达终点的。那么简单的思路便是判断如果数组中存在0,那么能否越过这些"0"就可以成为判断能否达到终点的依据。
那么为了判断"0"的位置是否能被越过,就需要记录前些位置能达到的最远距离----MaxIndex。当达到"0"的位置时,如果MaxIndex小于或者等于该点坐标,那么显然再接着往下跳跃是不可能的,因为在遇到0之前从任意点跳跃能达到的最远位置就是该点"0"的位置,就不可能继续往下跳了。
当然最远位置MaxIndex需要适时更新,如果MaxIndex的大小已经足矣达到终点,那么就返回true更新的依据显然是取遍历过程中跳跃距离的最大值。
代码如下:
class Solution {
public boolean canJump(int[] nums) {
int coveredIndex = 0;
if(nums.length == 1){
return true;
}
//当coveredIndex >= nums.length - 1就没必要循环了,因为已经可以到达终点
for (int index = 0; index <= coveredIndex && coveredIndex < nums.length - 1; index++) {
coveredIndex = Math.max(nums[index] + index, coveredIndex);
if(nums[index] == 0 && coveredIndex <= index){
return false;
}
}
return true;
}
}
明显的代码中我并没有利用MaxIndex作为参数名,而是利用的coveredIndex。
显然,coveredIndex更能将此跳跃过程形象化,因为题中给出的是跳跃的最大距离。那么我们明显可以将某点跳跃的最大距离引申为其能覆盖的距离,我们可以在被覆盖距离内任意的移动,可以到达其任意位置,如果某点的覆盖距离大于当前覆盖距离,就将当前覆盖距离更新。如果已经覆盖到终点,就返回ture。
那么如果覆盖距离没有再做更新,并且未覆盖到终点,也就是前文遇到"0"的情况,此时就是不可到达终点的。
这里提到的"如果覆盖距离没有再做更新"也可以引申出另外一种代码写法,如下:
class Solution {
public boolean canJump(int[] nums) {
int coveredIndex = 0;
//只有一个元素必然符合题意
if(nums.length == 1){
return true;
}
//index <= coveredIndex很关键,保证了下标只在能运动的范围类移动
//如果范围类一直不存在又增加被覆盖长度的元素致使其大于或等于数组长度,就是不存在的
for (int index = 0; index <= coveredIndex; index++) {
coveredIndex = Math.max(nums[index] + index, coveredIndex);
if(coveredIndex >= nums.length - 1){
return true;
}
}
return false;
}
}
值得注意的是,对于index的控制必须是index <= coveredIndex
因为我们能且只能在当前覆盖范围内移动。当未达到终点就需要在当前覆盖范围下寻找能增加覆盖范围的点,如果已经到达覆盖范围的末尾且无法继续增加覆盖范围的话就是不可达到终点的(覆盖范围末尾元素为0,如果大于0那么显然是可以增大范围的)
容易犯的错误:
刚开始接触贪心的话对于本题可能会犯的错误(比如我...)。
最开始没有记录当前能达到的最远距离,而是直接判断当前最大跳跃后所到达的点是否为"0",并且将index更新为跳跃后的点,如果为"0"就不更新index,转而continue,寻找当前位置下一个点。
但这样是有问题的,因为在最远跳跃的途中可能存在更大跳跃的点,而直接跳到最远位置就将这些点忽略了,如{2, 8, 1, 0, 4}这样的数组利用上述逻辑就是不可到达的,甚至会死循环。
当然也存在解决方法,那就是写成回溯——那就不是在做贪心啦。
最后总结本题的贪心思路:
我们只需要尽可能地增大覆盖范围直至覆盖到终点,如果不能就是不可能到达终点的!
注:coveredIndex思路参考《代码随想录》卡尔老师的视频讲解。
453

被折叠的 条评论
为什么被折叠?



