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.
Example
Ignored Case: time limitation
Solution 1: Backtracking
Cannot solve time limitation case
Consideration
- We start from the first index, and jump to every index it can jump to. If the index reaches the end index, return true.
==Time complexity: O(2^n), where n is the length of the array. Space complexity: O(n). Recursion requires additional memory for the stack frames. ==
class Solution {
public boolean canJump(int[] nums) {
return canJumpFromPosition(0, nums);
}
public boolean canJumpFromPosition(int position, int[] nums) {
if (position == nums.length - 1) {
return true;
}
int furthestJump = Math.min(position + nums[position], nums.length - 1);
for (int nextPosition = furthestJump; nextPosition > position; nextPosition--) {
if (canJumpFromPosition(nextPosition, nums)) {
return true;
}
}
return false;
}
}
Solution 2: dynamic programming top-down
Consideration
- We use an array to store the result of each index. If the index can jump to the end, the result is GOOD. If cannot, the result if BAD. If haven’t been visited, the result is UNKOWN.
Time complexity: O(n^2). For every element in the array, say i, we are looking at the next nums[i] elements to its right aiming to find a GOOD index. nums[i] can be at most n, where n is the length of array nums.
==Space complexity : O(2n) = O(n). First n originates from recursion. Second n comes from the usage of the memo table. ==
enum Index {
GOOD, BAD, UNKOWN
}
class Solution {
Index[] memo;
public boolean canJump(int[] nums) {
memo = new Index[nums.length];
for(int i = 0; i < nums.length; i++)
memo[i] = Index.UNKOWN;
memo[nums.length-1] = Index.GOOD;
return canJumpFromPosition(0, nums);
}
public boolean canJumpFromPosition(int position, int[] nums) {
if(memo[position] != Index.UNKOWN)
return memo[position]==Index.GOOD?true:false;
int furthestJump = Math.min(position+nums[position], nums.length-1);
//If we start from position, the last testing case will be time limited.
for(int nextPosition = furthestJump; nextPosition >= position+1; nextPosition--) {
if(canJumpFromPosition(nextPosition, nums)) {
memo[position] = Index.GOOD;
return true;
}
}
memo[position] = Index.BAD;
return false;
}
}
Solution 3: dynamic programming bottom-up
Consideration
- Top-down to bottom-up conversion is done by eliminating recursion.
- We start from the right end of the array. When we query to the right of this position, the memo already stored a result. We can hit the memo array.
Time complexity : O(n^2). For every element in the array, say i, we are looking at the next nums[i] elements to its right aiming to find a GOOD index. nums[i] can be at most nn, where nn is the length of array nums.
Space complexity: O(n). We use memo array to store the result.
enum Index {
GOOD, BAD, UNKOWN
}
class Solution {
Index[] memo;
public boolean canJump(int[] nums) {
memo = new Index[nums.length];
for(int i = 0; i < nums.length; i++)
memo[i] = Index.UNKOWN;
memo[nums.length-1] = Index.GOOD;
//iterate from the right end of the array
for(int i = nums.length-2; i >= 0; i--) {
int furthestJump = Math.min(i+nums[i], nums.length-1);
for (int j = i + 1; j <= furthestJump; j++) {
if(memo[j] == Index.GOOD) {
memo[i] = Index.GOOD;
break;
}
}
}
return memo[0] == Index.GOOD;
}
}
Solution 4: greedy (very clever one)
Consideration
- We start from the right end of the array. If the current index i of the considering number plus nums[i] is not less than the last index of the array, then the current index can reach to the end. We store the current index as the lastPos to be considered.
- Next time, we only need to consider if the current index can reach to the lastPos. If yes, then this index can finally reach to the end.
- At last, we only need to see if the lastPos is equal to 0.
Time complexity: O(n), space complexity: O(1), We are not using any extra memory.
class Solution {
public boolean canJump(int[] nums) {
int lastPosition = nums.length-1;
//iterate from the right end of the array
for(int i = nums.length - 2; i >= 0; i--) {
if(i+nums[i] >= lastPosition)
lastPosition = i;
}
return lastPosition == 0;
}
}
References