这道题是一个判断“能不能”的问题,所以想到可以使用动态规划来解决,DP的几个要素如下:
state: f[i]表示能否跳到第i个位置
function: f[i] = OR(f[j], j < i && j能够跳到i)
initialize: f[0] = truel
answer: f[n - 1]
这种方法的时间复杂度为O(n ^ 2),空间复杂度为O(n),在LeetCode上没有通过,得到了TLE的结果,不过这种思想还是很值得学习,代码如下:
// Method One: Dynamic Programming
public class Solution {
public boolean canJump(int[] nums) {
if(nums == null || nums.length == 0) return false;
boolean[] can = new boolean[nums.length];
can[0] = true; // initialize
for(int i = 1; i < nums.length; i++){
for(int j = 0; j < i; j++){
if(can[j] && j + nums[j] >= i){
can[i] = true;
break;
}
}
}
return can[nums.length - 1];
}
}
这道题目的正确方法应该是使用Greedy Algorithm,使用变量记录所能达到的最远距离,初始化为nums[0],然后从nums[1]开始对数组进行遍历,在每一次循环中检查当前的最大步数是否大于当前的index && nums[i] + i是否大于当前的最远距离,如果是的话则更新最远距离为nums[i] + i。当循环结束之后,只需要判断最远距离是否大于nums.length - 1即可,时间复杂度为O(n),空间复杂度为O(1),代码如下:
// Method Two: Greedy
public class Solution{
public boolean canJump(int[] nums){
if(nums == null || nums.length == 0) return false;
int farthest = nums[0];
for(int i = 1; i < nums.length; i++){
if(i <= farthest && nums[i] + i >= farthest){
farthest = nums[i] + i;
}
}
return farthest >= nums.length - 1;
}
}