Jump Game
Table of Contents + β
Jump Game looks like a maze puzzle. You stand at the start. Each spot tells you how far you can jump. The question is simple to ask but tricky to answer fast. Can you reach the last spot at all? The slow way checks every possible path. The fast way only tracks one number. That gap is what the interviewer wants to see.
π― The Problem
You get an array of numbers and must find out if you can reach the last position.
- Each number is the most steps you can jump forward from that position.
- You start at position
0. - The goal is the last index.
- Return
trueif some set of jumps lands you there. - Return
falseif you get stuck before the end.
Let us say the array is [2, 3, 1, 1, 4]. From position 0 the value is 2. So you can jump 1 or 2 steps forward.
Input: nums = [2, 3, 1, 1, 4]Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.Now look at a case where you cannot make it. The zero is the trap. If you land on a 0 and it is not the last spot, you cannot move.
Input: nums = [3, 2, 1, 0, 4]Output: false
Explanation: You always reach index 3 with value 0, so you stop before the end.Here is a picture of the second case. Each box shows how far you can jump from there. The 0 box has no arrow out.
π’ Approach 1: Recursion (Brute Force)
Try every possible jump from every spot.
The idea:
- A recursion is a function that calls itself on a smaller piece of the same problem.
- From position
0, try jumping1step, then2, up to the value there. - From each new spot, try every jump again.
- If any chain of jumps reaches the end, the answer is
true.
Why it is weak:
- You visit the same spots again and again through different paths.
- The branches keep splitting, so the time is about O(2^n).
- On a big array this becomes painfully slow.
Here is the plain recursion code:
def can_jump(nums): def dfs(index): if index >= len(nums) - 1: return True return any(dfs(index + step) for step in range(1, nums[index] + 1))
return dfs(0)β‘ Approach 2: Recursion With Memory (Better)
The idea in one line: store each spotβs answer the first time you compute it, then reuse it.
The idea:
- This is dynamic programming, which is recursion plus a memory of past answers.
- Each spot has a fixed answer: can you reach the end from here, yes or no.
- Compute it once, save it, never recompute it.
Why it is better:
- No spot is solved twice. So the repeated work is gone.
- Time drops to O(nΒ²). For each spot you still scan the spots it can reach.
Why it is still not best:
- It uses O(n) extra space for the memory.
- It still does O(nΒ²) work. We can do the whole thing in one pass.
Here is the memoized recursion code:
from functools import lru_cache
def can_jump(nums): @lru_cache(None) def dfs(index): if index >= len(nums) - 1: return True return any(dfs(index + step) for step in range(1, nums[index] + 1))
return dfs(0)π Approach 3: Greedy Farthest Reach (Best)
The idea in one line: track only the farthest index you can reach so far.
The idea:
- Keep one number, the farthest index reachable.
- To reach the end, all that matters is whether your reach ever covers the last index.
- You never need the exact path, only how far forward you can stretch.
How it works:
- Walk the array from left to right.
- If the current index is past your reach, you can never stand here. Return
false. - Otherwise update reach to the bigger of the old reach and
i + nums[i]. - If the loop finishes without getting stuck, return
true.
Why it is fast:
- One pass through the array. So it is O(n).
- Just one variable, so O(1) extra space.
- Greedy means you keep the single best reach and trust it.
Here is a dry run of the greedy reach on [2, 3, 1, 1, 4]. Watch the reach grow until it covers the last index.
Steps to Solve
- Start with
reach = 0. This is the farthest index you can get to. - Walk through the array with the index
ifrom start to end. - If
iis greater thanreach, you cannot stand here. Returnfalse. - Update
reachto the bigger ofreachandi + nums[i]. - If
reachalready covers the last index, you can stop early and returntrue. - If the loop finishes without getting stuck, return
true.
This Python version tracks the farthest reach in a plain variable and loops once.
def can_jump(nums): reach = 0 # farthest index we can get to for i, step in enumerate(nums): if i > reach: # cannot stand here return False reach = max(reach, i + step) # best reach so far return True
nums = [2, 3, 1, 1, 4]print(can_jump(nums))The output of the above code will be:
TrueLet us walk through the Python version line by line, because the greedy idea lives in just a few lines.
reach = 0 sets up the one number we care about. It is the farthest index we can currently get to. At the start we have only reached position 0.
for i, step in enumerate(nums): walks the array. Here i is the position and step is how far we can jump from it. We need both, so enumerate gives them together.
if i > reach: return False is the trap check. If the current position is beyond our farthest reach, we never could have arrived here. So the end is impossible and we stop.
reach = max(reach, i + step) is the heart of the greedy move. From this spot we can stretch to i + step. We keep whichever is larger, the old reach or this new one. We never need the path, only the best reach.
return True runs if we finished the loop without ever getting stuck. That means our reach always covered the next spot, so the end is reachable.
β±οΈ Time and Space Complexity
The recursion tries every path, so it is very slow and can repeat work. Adding memory turns it into dynamic programming, which is faster but still scans pairs of spots. The greedy way only keeps one number and one loop. So it trades nothing and still wins. That takes the time all the way down to O(n) with O(1) extra space.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Brute force recursion | O(2^n) | O(n) |
| Dynamic programming | O(nΒ²) | O(n) |
| Greedy farthest reach | O(n) | O(1) |
Tip
In an interview, say the recursion idea first to show you understand the problem. Then explain that you only ever need the farthest reach. That single insight is what turns the slow solution into the fast one.
π§© Key Takeaways
- β You only need one number, the farthest index you can reach so far.
- β
If the current position is past your reach, you are stuck and the answer is
false. - β
At each spot, update the reach to the bigger of the old reach and
i + nums[i]. - β Greedy works here because only the best reach matters, not the exact path.
- β This runs in O(n) time with O(1) extra space, much better than recursion.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does the Jump Game problem ask you to return?
Why: Jump Game asks a true or false question: can you reach the last index starting from index 0.
- 2
In the greedy solution, what does the reach variable hold?
Why: reach is the farthest index reachable so far, updated as max(reach, i + nums[i]).
- 3
When does the greedy solution return false?
Why: If i is past reach, you could never have arrived at i, so the end is unreachable.
- 4
What is the time and space complexity of the greedy approach?
Why: One pass through the array is O(n), and a single reach variable is O(1) extra space.