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.
[分析] 暴力做法是在每个位置 i, 跳 1 到 nums[i]步,看是否能够达到最后,妥妥超时。超时的case正好是无数的 1, 让我想到如果数组中的元素全部是正数,则必然可以跳到最后,因此关键是查看数组中的那些 0 是否可以被跳过,于是产生了方法2,觉得肯定有更优的。翻看自己的历史记录,代码上都比自己精简,更让人气愤的是不理解,orz。网上找了大神们的解析,理解了,而且发现自己之前被Accept的3种做法仅剩1种现在还能被Accept,其余一种就是
http://blog.csdn.net/kenden23/article/details/17242835 这篇博客指出的leetcode老test case的漏网之鱼,一种是递归的实现导致statck overflow。非常赞同该博客指出的此题关键是明确结束条件,方法2的结束条件是判断所有的 0 是否可以被跳过,效率是O(n^2), 两篇参考博客中的方法均是O(n),方法4的结束条件是:
记录lastJump的位置,循环i到lastJump,所有位置,找出其中的最大值maxJump =max{ i+A[i]};如果这个区间内的最大值maxJump <= lastJump,那么就返回假,因为没有任何一个位置可以跳出这个位置。 如果没有这样的位置,一直可以跳到最后,那么就返回为真。
方法3, 我的理解,贪婪地往前跳,循环结束的条件是要么到最后了要么无法继续往前跳了。
[PS] ref2博主Code_Ganker认为这题属于DP,希望自己对各种算法思想的理解在不断练习中加深。发现巧妙的解法是一件让人开心的事儿。
[ref]
http://blog.csdn.net/kenden23/article/details/17242835
http://blog.csdn.net/linhuanmars/article/details/21314059
public class Solution {
// Method 4: O(n)
// http://blog.csdn.net/kenden23/article/details/17242835
public boolean canJump (int[] nums) {
int lastJump = 0, maxJump = 0;
for (int i = 0; i < nums.length - 1; i++) {
maxJump = Math.max(maxJump, i + nums[i]);
if (i == lastJump) {
if (maxJump == lastJump) return false;
lastJump = maxJump;
}
}
return true;
}
// Method 3: O(n), DP
// http://blog.csdn.net/linhuanmars/article/details/21314059
public boolean canJump3(int[] nums) {
if (nums == null || nums.length == 0)
return true;
int maxJump = 0;
int last = nums.length - 1;
for (int i = 0; i <= maxJump && i < last; i++) {
maxJump = Math.max(maxJump, i + nums[i]);
}
if (maxJump < last)
return false;
else
return true;
}
// Method 2: O(n^2), 依次判断数组中0是否可以被跳过
public boolean canJump2(int[] nums) {
int lastZero = -1, currZero = -1;
int i = 0;
int N = nums.length;
while (i < N) {
int j = 0; // index which is expected to jump pass currZero
while ( j < currZero) {
if ((currZero != N - 1 && nums[j] > (currZero - j))
|| (currZero == N - 1 && nums[j] >= (currZero - j))) { // currZero can be skipped
lastZero = currZero;
break;
} else {
j++;
}
}
if (j == currZero) return false;
// search the next zero position
while (i < N) {
if (nums[i] == 0) {
currZero = i;
break;
} else {
i++;
}
}
i++;
}
return true;
}
// Method 1: time out
public boolean canJump1(int[] nums) {
return jump(nums, 0, nums.length - 1);
}
private boolean jump(int[] nums, int pos, int last) {
if (pos >= last)
return true;
for (int step = 1; step <= nums[pos]; step++) {
if (jump(nums, pos + step, last))
return true;
}
return false;
}
}