题目链接:45. Jump Game II
题目大意:与之前的跳跃游戏一样,从下标0出发,查看是否能跳跃到数组的最后一个下标。数组的每个元素都是能跳跃的距离,现在要求输出跳跃到最后下标的最小步数。
注意点:
- 这次要求所给的数组都能到达最后下标,即无需考虑到达不了的情况
- 不一定每次都走最大的距离,才能最快到达最后下标,故要改变之前的贪心策略
- 注意判断数组只有一个元素的情况
一.算法设计
这次要在第一个跳跃游戏的基础下,添加一个count数组,储存每个结点到达下标所用的最小跳跃次数,但是要记得将第一个下标的跳跃次数设置为0,即不需要跳跃即可到达。
每个结点找出所能到达的最远距离,如果这个最远距离小于n-1即最后下标,那么将count数组对应下标的元素赋值,该值为count[i]+1即到达该i结点的次数+1和它本身的次数的最小值
count[max_num] = min(count[i]+1, count[max_num]);
当最远距离大于最大下标,也亦然,只不过不是赋值最远距离下标而是赋值n-1.
最后count[n-1]所储存的一定是到达该下标的最少次数,这可以通过将问题分解成许多子问题来思考,因为子问题也是找到达前一个点的最少步数,所以最少步数的和也一定是到达终点的最少步数。
二.算法实现
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
if(n == 1) return 0;
int max_num = 0;
int count[30000]={0}; //要让count[0] = 0
for(int j = 1; j < 30000; j++){
count[j] = 300000;
}
for(int i = 0; i < n; i++){
max_num = max(max_num, i+nums[i]);
if(max_num <= n-1) count[max_num] = min(count[i]+1, count[max_num]);
else count[n-1] = min(count[i]+1,count[n-1]);
}
return count[n-1];
}
};
三.算法改进
当然也可以不用维持这一个count数组,只需要每一次所要跳跃的选择都选择能跳跃最远的结点。怎么为能跳跃最远呢,不仅要当前的下标大,还与数组元素相关
next_max=max(next_max,nums[i]+i);
这样选择多次,直到判断最远距离大于最远下标,即可输出选择的次数。
class Solution {
public:
int jump(vector<int>& nums) {
if(nums.size()<2){
return 0;
}
int level=0,current_max=0,next_max=0,i=0;
while(i<nums.size()){
level++;
for(;i<=current_max;i++){
next_max=max(next_max,nums[i]+i);
if(next_max>=nums.size()-1) return level;
}
current_max=next_max;
}
return level;
}
};