45.跳跃游戏Ⅱ
45.跳跃游戏Ⅱ
题目
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例 1:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: [2,3,0,1,4]
输出: 2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
55.跳跃游戏中可以得到一点启发,如果我们去记录跳跃的路径,也就是怎么跳是很麻烦的。我们可以转化为最大覆盖范围的问题。
最少的跳跃次数达到数组的最后一个位置,也就是最少次数增加覆盖范围使覆盖数组的最后一个位置。这样就不用考虑是怎么跳的,在本次跳跃中,覆盖范围都是能跳到的。
错误解放
那么覆盖范围每增加一次,跳跃的次数也增加一次。
题目说总是可以达到数组的最后一个位置,那么就不用考虑能不能到的问题了。
如果范围没有更新,说明之前的跳跃也能到本次跳的最远的地方,那么就不用增加跳跃次数了。
所以重点在关注范围的更新,那么就需要本次的cover和上次的cover比较才知道是否更新。
class Solution {
public int jump(int[] nums) {
int len = nums.length;
int cover=0,count=0;
for(int i=0;i<len-1;i++){
int preCover = cover;
cover = Math.max(cover,i+nums[i]);
if(preCover != cover) count++;
if(cover>=len-1) return count;
}
return count;
}
}
当测试用例为[7,0,9,6,9,6,1,7]的时候,发现每次范围更新的时候并不一定是在本轮跳跃中可以跳的最远的地方。
上述算法结论是4次,但其次两次就可以了。之前count更新的时机错了,需要思考count什么时候更新?并不是比当前范围更大就走这一步,而是在本次的覆盖范围内,选择下一次能跳的最远的跳。从nums[0]-nums[7]取到下一跳最大的范围时候就可以+1了,这样需要比较是否是最大,但是是没办法比较的。不管怎么样,只要i==cover时,说明这一轮结束了,在这一轮中肯定已经得出的最大的覆盖范围作为下一轮能选起点的终止位置,此时肯定会进行下一轮了(如果有的话),因为本轮能取的已经取完了,此时count++
正确解法
indexCover 表示此轮能够达到的最大距离
只要i==indexCover,说明这一轮结束了,已经跳到最后了。
这一轮需要做什么事?
不断的比较cover与i+nums[i],得出这一轮跳了之后能够达到的最远距离,也就是下一轮可跳的最远距离。
如果cover>=len-1
,说明下一轮一定可以跳到终点,那么返回count+1。
如果不是,那么说明下一轮不能跳到终点。还需要继续跳。
此轮结束时,需要count++
。说明进行下一跳了,那么还需要更新下一跳可以跳的最大范围。也就是indexCover=cover
。
class Solution {
public int jump(int[] nums) {
int len = nums.length;
if(len==1) return 0;
int cover=0,count=0,indexCover=0;
for(int i=0;i<len-1;i++){
cover = Math.max(cover,i+nums[i]);
if(cover>=len-1)return count+1;
if(i==indexCover){ //当这一轮结束时,更新本轮能到最大范围,进行下一轮跳跃
count++;
indexCover = cover;//indexCover等于本轮跳之后的最大覆盖范围
}
}
return count;
}
}