题目链接:https://leetcode.com/problems/jump-game/
题目:
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.
解题思路:
这题用了局部最优与全局最优来解题。
虽然之前做过 45 Jump Game II ,但是几乎忘记怎么做的了,只能自己慢慢回想。
对于数组中的每一个数字,根据其值的不同,它对其后元素的覆盖范围也不同。
例如:[2,3,1,1,4]
2 的下标覆盖范围是 1,2(覆盖到的最大下标为 2)
3 的下标覆盖范围是 2,3,4(覆盖到的最大下标为 4)
1 的下标覆盖范围是 3(覆盖到的最大下标为 3)
1 的下标覆盖范围是 4(覆盖到的最大下标为 4)
4 的下标覆盖范围超出了数组大小
遍历数组中的每一个元素
- 如果其覆盖范围的最大下标(local)大于之前已覆盖到的最大下标(global),就更新覆盖到的最大下标值。此时,该最大下标可能超出了数组大小,也就是说,只要覆盖到的最大下标大于等于(数组长度 - 1),那么从当前元素经过若干跳肯定能到达数组末尾,因为它最大能跳到比数组末尾下标还要远的地方。
- 如果其覆盖范围的最大下标(local)小于等于之前已覆盖到的最大下标(global),则说明该元素的覆盖范围在其它元素覆盖范围之内,不能对结果产生影响,故直接跳过本次循环。
- 需要注意的是,如果当前元素的覆盖范围是 3,但其后 3 个元素的覆盖范围都小于等于当前元素覆盖的最大下标,并且这个最大下标远没有到达数组末端,也就是说元素的覆盖范围再也不能得到扩展了,故直接跳出整个遍历数组的循环。(e.g. [3, 2, 1, 0, 1])
- 当然,还有一些小细节要注意。若数组长度为 1 时,数组第一个元素也是最后一个元素,所以一定能到达数组末端。若数组长度大于 1 时,第一个元素为 0,该元素的覆盖范围再也不能扩展,所以一定不能到达数组末端。
代码实现:
public class Solution {
public boolean canJump(int[] nums) {
if(nums == null || nums.length == 0)
return false;
int len = nums.length;
if(len == 1)
return true;
if(nums[0] == 0)
return false;
int local = 0;
int global = 0;
int k = 0; // 记录上次更新global的元素的覆盖的范围(思路第3点)
for(int i = 0; i < len; i ++) {
local = nums[i] + i;
k --;
if(local <= global) {
if(k == 0)
break;
else
continue;
}
else {
global = local;
k = nums[i];
if(global >= len - 1)
return true;
}
}
return false;
}
}
71 / 71 test cases passed.
Status: Accepted
Runtime: 2 ms
补充:
http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/linhuanmars/article/details/21354751
网上大牛更精炼的做法:
这道题是动态规划的题目,所用到的方法跟是在Maximum Subarray中介绍的套路,用“局部最优和全局最优解法”。我们维护一个到目前为止能跳到的最远距离,以及从当前一步出发能跳到的最远距离。局部最优local=A[i]+i,而全局最优则是global=Math.max(global, local)。递推式出来了,代码就比较容易实现了。因为只需要一次遍历时间复杂度是O(n),而空间上是O(1)。
public boolean canJump(int[] A) {
if(A==null || A.length==0)
return false;
int reach = 0;
for(int i=0;i<=reach&&i<A.length;i++)
{
reach = Math.max(A[i]+i,reach);
}
if(reach<A.length-1)
return false;
return true;
}