LeetCode 45. Jump Game II

            大概题意和LeetCode 55. Jump Game 相似,但现在已经告诉我们终点是可到达,而要求的是到达终点的最短步数。

          已经告诉有解的话就省了一些麻烦,但即便不确定是否能够到达,我们也可以先运行一遍LeetCode 55 的代码跑一遍进行判断。

          和LeetCode 55 一样,我先用了dp的方法做了一下,时间复杂度为O(n2),递归关系也很简单,代码如下:

const int maxn = 1000 + 50 ;
int d[maxn] ;
const int INF = 10000000 ;

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size() ;
        if (n == 0) return 0 ;
        
        for (int i=0; i<n; i++) {
        	d[i] = INF ;
        }
        d[0] = 0 ;
        
        for (int i=0; i<n; i++) {
        	int s = nums[i] ;
        	for (int j=i+1; j<=min(n-1, i+s); j++) {
        		d[j] = min(d[j], d[i] + 1) ;
        	}
        }

        
        return d[n-1] ;
    }
};
          然而,数据规模比较大,TLE了。我也一直想说LeetCode的这个缺点,很多问题没有给出数据的规模,甚至连测试样例都没有。不过这也能逼自己去寻找更好更有鲁棒性的算法。

          之后我也想了一种贪心的算法。首先,对于任意位置i < j ,从起始点到达i 的所用的步数一定不会比到达j 所用的步数多。为什么呢?我们可以先设 k为去j 的路径中,在i 前的最后一步,易知k到i只要一步,否则就不是i前的最后的一步,而k到达j至少需要1步。

          所以我们就得到了一个贪心的策略,从终点出发,每次最大限度的往前走。

          具体要怎么实现呢?首先要调整数组,让其每个位置的数值为可达到的最远的位置,而每次的“前一步”就是第一个满足数组元素值 >= 当前位置的所对应的下标。搜索的过程可用上二分搜索。但此时的数组可能不是递增的,怎么办呢?稍作调整即可,将所有小于前一个数的位置的数值改成前一个数的数值。这并不影响我们的搜索,因为我们要找的第一个满足的位置肯定不是这些位置。

          具体代码如下,在最差的情况下时间复杂度为O (nlogn) 。

 

int b_search(int x, int y, int key, vector<int>& a) {
	int m ;
	while (x < y) {
		m = x + (y - x)/2 ;
		if (a[m] < key) x = m + 1  ;
		else y = m ; 
	}
	return x ;
}

class Solution {
public:
    int jump(vector<int>& nums) {
        int n = nums.size() ;
        if (n == 0) return 0 ;
        
        for (int i=0; i<n; i++) {
        	nums[i] += i ;
        	if (i && nums[i] < nums[i-1]) nums[i] = nums[i-1] ;
        }
        int index = n-1 ;
        int cnt = 0 ;
        
        while (index > 0) {
        	index = b_search(0, index, index, nums) ;
        	cnt++ ;
        }

        return cnt ;
    }
};

        





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值