Jump Game looks like it needs path-finding, but a single greedy scan settles it. It teaches a habit worth keeping: track one running number — the farthest you can reach — instead of simulating every possible jump.
Problem. Given an array nums where each value is the maximum jump length from that position,
return true if you can reach the last index starting from index 0, otherwise false.
Example: nums = [2, 3, 1, 1, 4] → true (e.g. jump 1 then 3 to the end). But nums = [3, 2, 1, 0, 4]
→ false — every route lands on the 0 at index 3 and gets stuck.
The slow way first
The brute-force idea is to try every jump: from index i you could land on i+1, i+2, … up to i + nums[i], and from each of those try again. Explored naively this branches into an exponential number of paths; even memoized as dynamic programming it is O(n²) (every index may scan all the indices it can jump to).
The question to ask: do I actually need to know which jumps I take? No. I only need to know whether the end is reachable at all.
The idea: track the farthest reach
Keep one number, reach: the farthest index reachable so far. Walk left to right. At each index i:
- If
i > reach, there is a gap I can never cross — returnfalse. - Otherwise
iis reachable, so I can extend my horizon:reach = max(reach, i + nums[i]).
If the scan finishes without getting stuck, the last index was always within reach — return true.
The key insight: you do not need the exact jumps. A position is reachable if and only if it sits within the farthest reach accumulated from everything to its left.
Walk through it
Step through the animation on [2, 3, 1, 1, 4]. The i pointer scans left to right; the reach marker underneath slides to the farthest index reachable so far. At i = 1, reach jumps to 4 (the last index) and never shrinks, so every later index is comfortably covered and we return true. The final step shows the trap case [3, 2, 1, 0, 4], where reach stalls at 3 and i = 4 falls past it.
Pseudocode
reach = 0 # farthest index reachable so far
for i from 0 to len(nums) - 1:
if i > reach: # a gap we cannot cross
return false
reach = max(reach, i + nums[i]) # extend the horizon
return true # made it through every indexThe Python solution
def can_jump(nums):
reach = 0
for i in range(len(nums)):
if i > reach:
return False
reach = max(reach, i + nums[i])
return Truereachis the only state we keep: the farthest index reachable using everything seen so far.if i > reachis the stuck check — the current index lies beyond the horizon, so the end is impossible.reach = max(reach, i + nums[i])extends the horizon;i + nums[i]is the farthest you can land fromi.- We never decrease
reach, and once it meets or passes the last index the rest of the scan trivially passes.
Complexity
| Case | Time | Notes |
|---|---|---|
| DP / brute force | O(n^2) (slow) | each index scans its jump range |
| Greedy (this solution) | O(n) (moderate) | one pass, one running max |
O(1) (fast)The greedy version uses O(1) extra space — just the single reach variable — and one pass. That is the payoff of asking what is the minimal fact I must track? instead of simulating every choice.
When this pattern shows up
When a problem asks "is it possible to reach / cover / complete" and each element bounds how far you can move, try carrying a single farthest-reach (or running-max) value in one left-to-right pass. Jump Game II, Gas Station, and interval-merging problems share this greedy shape.
Watch the zeros. A 0 does not fail on its own — it only traps you if reach cannot already jump over it.
The check that matters is i > reach, not "is this value zero." Test inputs like [0] (true) and
[1, 0, 1] (false) to make sure your reasoning holds.
Practice
For nums = [2, 3, 1, 1, 4], what is reach right after processing i = 1, and why does that already settle the answer?
1. What does the variable reach represent?
2. When does the algorithm return False?
3. Why is the greedy solution O(n) instead of O(n^2)?
4. For nums = [3, 2, 1, 0, 4], why is the answer False?