LeetCode 55. Jump Game

来源:互联网 发布:2015年网络歌曲 编辑:程序博客网 时间:2024/06/06 19:40

              本题的大概题意:给定一个整型数组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 ;    }







0 0
原创粉丝点击