贪心+回溯
当然要多快好省跑到终点~
首先想到便是贪心,只要最后一步能跳跃到终点就算成功。就有了如下方程:
locate + nums[locate] >= nums.size() - 1
当然最后一步到不了终点就失败了吗?显然不可能,那就需要回退到再上一次跳跃,少跳一格咯。联系到回溯的特点,有了如下方程:
for(int i=nums[locate];i>0;--i) jump(nums,locate+i)
加上退出条件,就有了如下代码:
class Solution {
public:
bool canJump(vector<int>& nums) {
if(nums.size()==0) return false;
if(nums.size()==1) return true;
return jump(nums,0);
}
bool jump(vector<int>& nums,int locate){
if(locate>=nums.size()-1) return true;
if(nums[locate]==0) return false;
for(int i=nums[locate];i>0;--i){
if(jump(nums,locate+i)) return true;
}
return false;
}
};
结果很可惜,挂在了最后两个用例上:
行不通考虑下一个方法
BFS
搜索算法解决这类题还是很方便的,实现也很简单,把第一个压入队列,并依次将其能够到达的几个点压入队列。依次类推到所有节点,若下一步能够到达终点就算成功。于是:
while(!que.empty()){
//取队首
Node tmp = que.front();
//依次压入,优先将最远的压入
for(int i=tmp.b;i>0;--i){
if(tmp.a+i >= length-1) return true;
que.push(list[tmp.a+i]);
}
que.pop();
}
考虑到BFS的特点,一个点可能被压入数次,加上visit数组记忆搜索:
for(int i=tmp.b;i>0;--i){
if(tmp.a+i >= length-1) return true;
if(visit[tmp.a+i]) continue;
que.push(list[tmp.a+i]);visit[tmp.a+i] = 1;
}
加上所有条件,如下:
class Solution {
public:
struct Node{
int a,b;
};
bool canJump(vector<int>& nums) {
int length = nums.size();
if(length==0) return false;
if(length==1) return true;
Node list[length];
for(int i=0;i<length;++i){
list[i].a = i;list[i].b = nums[i];
}
queue<Node> que;
que.push(list[0]);
int visit[length];memset(&visit,0,sizeof(int)*length);
while(!que.empty()){
Node tmp = que.front();
for(int i=tmp.b;i>0;--i){
if(tmp.a+i >= length-1) return true;
if(visit[tmp.a+i]) continue;
que.push(list[tmp.a+i]);visit[tmp.a+i] = 1;
}
que.pop();
}
return false;
}
};
虽然AC,结果还是不如人意
动态规划
这里的状态转移方程还是比较简单,推导过程就省略,能到达赋为1,不能为0,一直往后遍历即可。
class Solution {
public:
bool canJump(vector<int>& nums) {
int length = nums.size();
int dp[length];
memset(&dp,0,sizeof(int)*length);
dp[0] = 1;
for(int i=0;i<length;++i){
if(dp[i]){
for(int j=1;j<=nums[i];++j){
if(i+j>=length-1) return true;
dp[i+j] = 1;
}
}
}
return dp[length-1];
}
};
结果感人:
做一点小变换,把循环赋值省掉,dp[0]=255是为了统一后面的memset:
class Solution {
public:
bool canJump(vector<int>& nums) {
int length = nums.size();
char dp[length];
memset(&dp,0,sizeof(char)*length);
dp[0] = 255;
for(int i=0;i<length;++i){
if(dp[i]){
if(i+nums[i]>=length-1)
return true;
else
memset(&dp,1,sizeof(char)*(nums[i]+i+1));
}
}
return dp[length-1];
}
};
结果提升很大,但是还有更好的办法
题目特殊性
1.考虑到题目特殊性,如果能到达某一格,那么左侧的所有位置,都能到达。
2.数组中的每个元素都大于零,那一定能跳到终点。则题目可以转化为检测遇到的0能否跳过。
这两点都是考虑到了特殊性。不一定能够解决更复杂的情况。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。