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
.
解题思路:
因为数组中都是非负整数,所以跨越不过去的一定是0。而且要注意A[i]是能跳的最远距离,不是肯定跳这么远。
所以当只要脚下不是0,都可以用最远距离跳,肯定到头。一旦跳到0上,就从0这里往回走一个,再跳,看看是不是超过之前0的位置。如果超过0,就证明能跨过这个0,继续往前。如果还在这个0上,或者还没到0,下标就再往回一个,然后跳,继续判断是否已经跳过0。重复,直到回到了数列尽头。证明无论如何都不能跨过这个0了。返回false。
public class Solution { public boolean canJump(int[] A) { int step = 0; int base = 0; while(true){ if(step >= A.length - 1){ return true; } if(A[step] == 0){ base = step; while(step >= 0){ step--; if(step < 0){ return false; } if(step + A[step] > base){ break; } } } step += A[step]; } } }
不过上面的解法有缺陷,在最差情况下,111101,要花2*n的时间,才能判断结果为false。
下面介绍一个动态规划的算法。其实一开始也想到用dp,dp[i]定义为是否能到达i。dp[i] = dp[k] && (k + A[k] >= i),这里0<=k<i。用的还是上面的思路,还不如上面来的简单。后来从网友那里看到了一种更好的dp,http://blog.csdn.net/linhuanmars/article/details/21354751。
我们可以将dp[i]定义为以i为起点可以到达的最远距离,显然就是i+A[i],这是当前局部的最优。那么全局最优,也就是0-i的点可能到达的最远距离显然可能不是dp[i],因为可能i前面的点能跳的更远,这是全局最优,叫maxReach。
有了这个思想,我们一直往前遍历A,用当前最远距离dp[i]去更新全局最远距离maxReach。i最远只能到maxReach,因为这是当前最远能到的地方,如果i超过maxReach了,证明根本到不了这里,立刻返回false。
如果maxReach到A.length-1了,就说明可以到头,返回true。
public class Solution { public boolean canJump(int[] A) { int maxReach = 0; for(int i = 0; i < A.length; i++){ if(maxReach < i){ return false; } if(i + A[i] > maxReach){ maxReach = i + A[i]; } if(maxReach >= A.length - 1){ return true; } } return false; } }
这里我们再次看到,如何定义dp的子状态是dp能否顺利解决的关键。同样是以dp的视角,不同的状态定义得到的解法可能是完全不同的复杂程度。