题目描述
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例
说明
假设你总是可以到达数组的最后一个位置。
解题思路
刚开始想到的思路是递归,调用递归函数(参数携带表示位置的索引)返回从该位置到最后一个位置需要的最小跳数。
虽然递归法可以求解,但这并不是一个好的思路。不管是从时间还是空间来说消耗都非常大,时间复杂度是指数增长的,调用过多的递归函数会占用很多内存,而且如果数组长度到15以上或者20以上,递归法都会超时。
然后想到了一个好的思路是动态规划,这道题的描述和构造非常适合使用动态规划求解。第一个位置到最后一个位置的最小跳跃数,不妨构造一个数组表示每个位置到最后一个元素的最小跳跃数,从最后依次往前写入数据,直到写到第一个位置(到最后一个位置)的最小跳跃数。
从后往前写入每个位置到最后一个位置的最小跳跃数,初始化将最后一个位置的跳跃数置0,从倒数第二个位置开始向前遍历。该位置如果能直接跳到最后一个位置(该位置索引+该位置跳跃最大长度 大于或等于 最后一个位置的索引),则该位置最小跳跃数为 1;如果不能跳到最后一个位置,则该位置最小跳跃数为 他所能跳到的所有位置中最小跳跃数最小的值 加1。这样依次向前遍历,直到索引 i=0结束。得到第一个位置到最后一个位置的最小跳跃数。
动态规划代码
#include<vector>
class Solution {
public:
int jump(vector<int>& nums) {
int leng = nums.size();
int *p = new int[leng]; //p数组记录每个位置到最后一个位置的最小跳数
p[leng-1]=0; //初始化最后一个位置的跳数为0
for(int i=leng-2;i>=0;i--)
{
if(nums[i]==0)
p[i]=leng+1;
if(nums[i]+i>=leng-1) //如果自己能直接到达最后
{
p[i]=1;
}else{ //如果自己不能到最后
int min=p[i+1];
int index=i+1;
while(index<=i+nums[i]){
if(p[index]<min)
min=p[index];
index++;
}
p[i]=min+1; //该位置的最小跳数等于 --》他能到达的所有位置中跳数最小的+1
}
}
return p[0];
}
};
递归法(不是一个好方法)
#include<vector>
class Solution {
public:
//返回在该节点跳跃到最后一个节点需要跳跃的最小次数
int dfs(vector<int>& nums,int index){
if(index==nums.size()-1) //如果到最后一个节点,返回 1
return 0; //最后一步算0,前面每跳一步+1(因为最开始idnex=0算一步,结尾times+1)
if(index>=nums.size()||nums[index]==0)
return nums.size()+1; //返回一个很大的数
int max = nums[index]; //当前能跳跃的最大步数
int times = nums.size()+1; //设置最小跳跃次数
for(int i=1;i<=max;i++)
{
int rs = dfs(nums,index+i);
if(rs<times)
times = rs;
}
return times+1;
}
int jump(vector<int>& nums) {
// index表示当前索引,times表示跳跃次数
int index = 0;
int times = 0;
int result = dfs(nums,index);
return result;
}
};