问题描述
给你一个非负整数数组 nums
,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
提示:
1 <= nums.length <= 10^4
0 <= nums[i] <= 1000
示例
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
解题思路
这里我们可以从起始位置出发,根据当前可跳跃次数,来更新后面位置的最少跳跃次数。如果后面某个位置 j 是由当前位置 i 跳跃过去的,即当前位置最少需要跳跃 x 次,则判断 x+1 是否小于 i 的最小跳跃次数,如果小于,则更新它的值。
但是这样做存在大量重复遍历的节点,例如 nums=[5,1,1,1,1,1,1] ,在这里,我们从 0 开始跳跃两步即可抵达终点,按我们之前的方法却要遍历多 1, 2, 3, 4 这四个位置。因此,我们可以记录一下上一轮最远的跳跃位置,如果当前位置跳跃无法跳出上一轮的最远位置,就不需要再考虑这个位置了(因为跳跃次数一定比上一次的跳跃次数多)。
同时,在这种情况下,我们发现,每次更新最少跳跃次数,更新值都不超过上一次的更新值。这对我们有两个帮助:1,只要我们从某个点出发,最远跳跃位置达到了末尾,则可以终止判断了,已经找出了最少跳跃次数;2,每次更新最少跳跃次数时,我们无需与上一次保存的值进行比较。
最终的代码如下:
class Solution {
public:
int jump(vector<int>& nums) {
vector<int> dp(nums.size(), 0x7ffffff);
int tmp;
int pre_max = 0;
int max = 0;
int max_idx = nums.size() - 1;
dp[0] = 0;
for(int i = 0; i < nums.size(); i++){
if(i + nums[i] < max){
continue;
}
else{
pre_max = max;
max = (i + nums[i]) < nums.size() ? (i + nums[i]) : (max_idx) ;
}
if(pre_max == max_idx){
break;
}
tmp = dp[i] + 1;
for(int j = pre_max + 1; j <= max; j++){
dp[j] = tmp;
}
}
return dp[max_idx];
}
};
标签:力扣,位置,nums,int,max,45,II,次数,跳跃
From: https://www.cnblogs.com/greatestchen/p/16936660.html