一、自顶向下的动态规划(回溯)
利用memo
来记录某个点能否到最后的点,避免重复计算。
1
代表可以可以,-1
代表不行,0
代表还不知道。
class Solution {
public:
bool canJump(vector<int>& nums) {
vector<int> memo(nums.size());
memo.back()=1;//最后一个点自然能到最后一个点,因此初始化为1
return _canJump(nums,0,memo);
}
bool _canJump(vector<int>& nums, int index, vector<int>& memo){
if(memo[index]!=0){
return memo[index]==1?true:false;
}
if(nums[index]==0){
memo[index]=-1;
return false;
}
int longest = min(index+nums[index],(int)nums.size()-1);//该点能到达的最远的点
for(int i=index+1;i<=longest;++i)
if(_canJump(nums,i,memo)){
memo[i]=1;
return true;
}
memo[index]=-1;
return false;
}
};
二、自底向上的动态规划(消除回溯)
bool canJump(vector<int>& nums) {
if(nums.empty()) return false;
int size = nums.size();
vector<int> dp(size);
dp.back()=1;
for(int i=size-2;i>=0;--i){
int longest = min(i+nums[i],size-1);
for(int j=i+1;j<=longest;++j){
if(dp[j]==1){
dp[i]=1;
break;
}
}
}
return dp[0]==1;
}
三、贪心算法(效率最高)
从右向左迭代,始终只记录最左边的可以到达目标的节点。
bool canJump(vector<int>& nums) {
if(nums.empty()) return false;
int size = nums.size();
int lastPos = size-1;
for(int i=size-1;i>=0;--i)
if(i+nums[i]>=lastPos)
lastPos=i;
return lastPos==0;
}