您的位置:首页 > 其它

LeetCode 55. Jump Game

2016-11-23 21:43 405 查看
              本题的大概题意:给定一个整型数组nums,数组的每个值代表能从该位置向前走的最大的步数。一开始时玩家处于数组的第一个位置,问玩家能否到达最后一个位置。

          这道题我使用了两种方法,第一种方法是直接使用dp进行搜索:用一个数组vis来表示某个位置是否可达, 若可达则对应值为1,不可达则为0。我们很容易就能发现一个规律:若i 是可达的,那i+1 ~ i + nums[i] 也是可达的。因此,具体实现也很简单,我用的是记忆化搜索的写法,代码如下:

             

const int maxn = 1000 + 50 ;
bool vis[maxn] ;

void dfs(int x, vector<int>& nums, int n) {
if (vis[x] == true) return ;

vis[x] = true ;
int value = nums[x] ;
for (int i=1; i<=value; i++) {
int t = i + x ;
if (t >= n) return ;
dfs(t, nums, n) ;
}
return ;
}

class Solution {
public:
bool canJump(vector<int>& nums) {
memset(vis, 0, sizeof(vis)) ;
int n = nums.size() ;
if (n == 0) return true ;

dfs(0, nums, n) ;

return vis[n-1] ;
}
};
          由于对于每个i , 最多可能要向下搜索n - i 次,所以时间复杂度在最差的情况下,时间复杂度为O(n2) ;

       由于测试样例的数据规模并不大,所以这种时间复杂度的算法也能够通过这道题。

      但这道题的标签是贪心,说明使用贪心应该有时间复杂度更低的算法。于是我想到了另外一种做法:我们不进行搜索,直接用贪心的做法进行决策。每走到一个新的位置,我们需要选一个“最好”的下一步(所谓最好,就是走了这一步,如果有解的情况下,走这一步一定能达到目的地)。而这“最好”的一步就是再下一步能够去到最远的一步。为什么呢?我们先设当前位置为 i,能够再下一步去到最远的下一步为 j ,则能去到最远的地方为 j + nums[j] 。所有i + 1
~ j - 1 能到达的地方,包括了大于 j 的位置和小于等于j 的位置。对于小于等于j的位置,能到达的最远的地方依然不会超过 j + nums[j] ,这只是“白走了一步”而已;而对于所有大于j 的位置,j 均能够到达,因为j 能够到达所有j + 1 ~ j + nums[j] 的位置,而这些位置其他的下一步不一定能够到达。所以j 是最好的选择。如果走了j之后无法抵达终点,则无解。 

       具体代码如下,时间复杂度在最差的情况下依然为O(n2),但因为i大部分情况下不需要逐个遍历0 ~ n-1 的每一个值,所以依然加速了不少,通过测试样例的时间是上一种做法的1/10 而已。

       

class Solution {
public:
bool canJump(vector<int>& nums) {
int n = nums.size() ;
if (n == 0) return true ;

int i = 0 ;
while (i < n) {
if (i == n-1 ) return true ;
if (nums[i] == 0) return false ;
int maxstep = 0 ;
int nextstep = i ;

for (int j=i+1; j<=i + nums[i] && j < n; j++) {
if (maxstep < j - i + nums[j]) {
nextstep = j ;
maxstep = j - i + nums[j] ;
}
}
i = nextstep ;
}
return true ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 数组 贪心