给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
思路:本题对于55题难度增加了不少,但是思路是相似的,都是要看最大覆盖范围。
本题要计算最少步数那么就要想清楚什么情况下步数必须加一
局部最优:在当前可移动距离固定时,尽可能多走,如果还没到终点,则步数加一。
整体最优:用最小步数到达终点。
虽然思路是这样的但是写代码的时候还步数想跳多远就跳多远这样就不知道下一步最远能到达哪里了。
所以真正题解的时候,要从覆盖范围出发,不管怎么跳覆盖范围内是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦到达终点,得到的就是最小步数。
- 当移动下标达到最远距离时,步数就要加一来增加覆盖距离,最后的步数就是最小步数
- 这里还 有两种情况需要考虑,当移动下标达到了当前覆盖最远距离下标时:
- 如果当前覆盖范围的最远距离的下标不是集合终点,那么步数加一还要继续移动。
- 如果当前覆盖范围的最远距离的下标就是集合终点,那么步数就不用加一,因为不用再往后移动了。
解法一:
-
class Solution { public int jump(int[] nums) { int ans =0;//记录步数 int cur =0;//当前覆盖的最远距离下标 int next =0;//下一步覆盖的最远距离下标 for(int i=0;i<nums.length;i++) { // 更新下一步最远距离下标 next = Math.max(next, i+nums[i]); //遇到当前覆盖最远距离下标 if (i==cur) { //如果当前覆盖最远距离下标不是终点 if(cur!=nums.length-1) { cur =next;//更新当前覆盖最远距离下标 ans++;//需要走下一步 if (next>=nums.length-1) {//下一步的覆盖范围已经包括终点,结束循环 break; } }else break;//当前覆盖最远下标是终点,不需要再走 } } return ans; } }
针对解法一的情况,可以统一处理,既移动下标只要遇到当前最远覆盖距离的下标,步数加一,不需要考虑是不是终点的问题。
想要达到这样的效果只需要让移动下标的最远只能移动到下标为nums()-2的地方即可,以为当移动下标指向nums()-2时:
- 如果移动下标等于当前覆盖的最远距离的下标,则需要再走一步,最后一步无论如何都可以走到终点。
- 如果移动下标不等于当前最远覆盖距离的下标则说明当前最远覆盖距离的下标已经到达终点,不需要再走一步了。
lass Solution {
public int jump(int[] nums) {
int ans =0;//记录走的步数
int cur =0;//当前最远覆盖距离的下标
int next =0;//下一步最远覆盖距离的下标
for(int i=0;i<nums.length-1;i++) {//注意这里是小于nums()-1
next = Math.max(next, i+nums[i]);//更新下一次最远覆盖距离下标
if(i==cur) {//遇到当前最远覆盖距离的下标
cur = next;//更新当前最远覆盖距离下标
ans++;
}
}
return ans;
}
}