LeetCode 55. Jump Game

              本题的大概题意:给定一个整型数组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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值