55. Jump Game - Explanation
Description
You are given an integer array nums where each element nums[i] indicates your maximum jump length at that position.
Return true if you can reach the last index starting from index 0, or false otherwise.
Example 1:
Input: nums = [1,2,0,1,0]
Output: trueExplanation: First jump from index 0 to 1, then from index 1 to 3, and lastly from index 3 to 4.
Example 2:
Input: nums = [1,2,1,0,1]
Output: falseConstraints:
1 <= nums.length <= 10000 <= nums[i] <= 1000
Topics
Recommended Time & Space Complexity
You should aim for a solution with O(n) time and O(1) space, where n is the size of input array.
Hint 1
A brute force approach would be to recursively explore all paths from index 0 to its reachable indices, then process those indices similarly, returning true if we reach the last index. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works.
Hint 2
Instead of processing the array from index 0, start from the last index. Let the target index be goal = n - 1. Iterate in reverse from index n - 2.
Hint 3
At each iteration, we check whether the current index can reach goal. If it can, we update goal to the current index, as reaching the current index means we can also reach the goal.
Hint 4
To determine if we can reach the last index, the goal should be 0 after the iteration. Otherwise, reaching the last index is not possible.
Prerequisites
Before attempting this problem, you should be comfortable with:
- Recursion - Understanding how to break down problems into smaller subproblems by exploring all possible paths
- Dynamic Programming (Memoization) - Caching results of subproblems to avoid redundant computation
- Greedy Algorithms - Recognizing when a locally optimal choice leads to a globally optimal solution
- Array Traversal - Iterating through arrays both forward and backward
1. Recursion
Intuition
This problem asks whether we can reach the last index of the array starting from the first index.
At every position i, the value nums[i] tells us the maximum jump length from that index.
So from index i, we can jump to any index between i + 1 and i + nums[i].
Using recursion, we try all possible jumps from the current index and see if any path eventually reaches the last index.
The recursive function represents:
"Is it possible to reach the last index starting from index i?"
If we ever reach the last index, we know the answer is true.
Algorithm
- Define a recursive function
dfs(i):iis the current index
- If
iis already at the last index:- Return
true
- Return
- Compute the farthest index we can jump to from
i:end = min(last_index, i + nums[i])
- Try all possible next positions from
i + 1toend:- Recursively call
dfs(j) - If any call returns
true, returntrue
- Recursively call
- If none of the jumps lead to the end:
- Return
false
- Return
- Start the recursion from index
0 - Return the final result
Time & Space Complexity
- Time complexity:
- Space complexity:
2. Dynamic Programming (Top-Down)
Intuition
This problem asks whether we can reach the last index of the array starting from index 0.
At each index i, the value nums[i] tells us how far we can jump. From there, we can choose any next index within that jump range.
The plain recursive approach explores all possible jumps, but it repeats the same work many times.
To avoid this, we use top-down dynamic programming (memoization).
The recursive function represents:
"Can we reach the last index starting from index i?"
Once we know the answer for an index, we store it so we never recompute it.
Algorithm
- Create a memo map
memo:memo[i]stores whether the last index is reachable from indexi
- Define a recursive function
dfs(i):iis the current index
- If
iis already inmemo:- Return the stored result
- If
iis the last index:- Return
true
- Return
- If
nums[i] == 0:- No jumps are possible, so return
false
- No jumps are possible, so return
- Compute the farthest index we can jump to from
i - Try all next indices within the jump range:
- If any recursive call returns
true, storetrueinmemo[i]and return it
- If any recursive call returns
- If none of the jumps work:
- Store
falseinmemo[i]and return it
- Store
- Start the recursion from index
0 - Return the final result
class Solution:
def canJump(self, nums: List[int]) -> bool:
memo = {}
def dfs(i):
if i in memo:
return memo[i]
if i == len(nums) - 1:
return True
if nums[i] == 0:
return False
end = min(len(nums), i + nums[i] + 1)
for j in range(i + 1, end):
if dfs(j):
memo[i] = True
return True
memo[i] = False
return False
return dfs(0)Time & Space Complexity
- Time complexity:
- Space complexity:
3. Dynamic Programming (Bottom-Up)
Intuition
We want to know if we can reach the last index starting from index 0.
Instead of using recursion, we can solve this using bottom-up dynamic programming by working backwards from the end of the array.
The idea is simple:
- mark positions that can reach the end
- then check earlier positions to see if they can jump to any of those “good” positions
If index i can jump to any index j that is already reachable, then i is also reachable.
Algorithm
- Let
nbe the length of the array. - Create a boolean array
dpof sizen:dp[i] = truemeans the last index is reachable from indexi
- Set the base case:
dp[n - 1] = truesince the last index can trivially reach itself
- Iterate
ifromn - 2down to0: - For each index
i:- Compute the farthest index we can jump to:
end = min(n, i + nums[i] + 1) - Check all reachable positions from
i:- if any
dp[j]istrue, then setdp[i] = true
- if any
- Compute the farthest index we can jump to:
- After filling the array, return
dp[0]
Time & Space Complexity
- Time complexity:
- Space complexity:
4. Greedy
Intuition
We want to check if we can reach the last index starting from index 0.
Instead of trying all possible jumps, we can think about the problem in reverse:
- ask which positions can eventually reach the end
- then move backward to see if earlier positions can reach those positions
We keep a variable called goal:
- it represents the leftmost index that we must be able to reach
- initially, the goal is the last index itself
As we move backward through the array:
- if from index
iwe can jump to the currentgoal(or beyond), then indexibecomes the new goal
At the end, if index 0 becomes the goal, it means we can reach the last index.
Algorithm
- Initialize
goalas the last index of the array. - Iterate from the second last index down to index
0. - For each index
i:- Check if
i + nums[i] >= goal - If yes, update
goal = ibecause indexican reach the previous goal
- Check if
- After the loop finishes:
- If
goal == 0, returntrue - Otherwise, return
false
- If
Time & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Confusing Jump Value with Index
The value nums[i] represents the maximum jump length, not the destination index. From position i, you can reach any index in [i + 1, i + nums[i]], not just i + nums[i]. Treating the jump value as a fixed destination misses valid shorter jumps.
Not Handling Zero Values Correctly
A zero at position i means you cannot move forward from that position. If all paths lead to a position with nums[i] == 0 before reaching the end, the answer is false. Ensure your algorithm properly detects when you are stuck.
Iterating in the Wrong Direction for Greedy
The greedy approach works backward, updating the goal position. A common mistake is iterating forward and incorrectly maintaining state. When going backward, the condition i + nums[i] >= goal correctly checks reachability.
Sign in to join the discussion