The problem
You stand at index 0 of an array nums. From index i you may jump forward by any distance from 1 up to nums[i]. Return the minimum number of jumps to reach the last index. The input guarantees the end is reachable.
Input: nums = [2, 3, 1, 1, 4]
Output: 2Jump from index 0 to index 1 (one step), then from index 1 jump 3 steps to index 4.
How to think about it
Start with brute force. Try every jump length from every index recursively, or run a DP where dp[i] is the fewest jumps to reach i and each index updates everything it can reach. The DP is O(n²) in the worst case, since each index can reach up to n others. That is too slow for n = 10⁴ with big jump values.
The key insight: jumps are BFS levels. With 0 jumps you can stand only at index 0. With 1 jump you can reach any index in [1, nums[0]]. With 2 jumps you can reach anything reachable from that window, and so on. Each “level” is a contiguous window of indices, because if you can reach index k you can also reach everything before it. So you don’t need a queue; you only need the right edge of the current window (end) and the furthest index reachable from inside it (far).
When you walk past the edge, you must jump. Scan left to right, updating far = max(far, i + nums[i]). When i hits end, every index in the current level has been considered, so you take one more jump and the next level ends at far. You never decide which index to jump from; you only count how many windows you pass through.
Which pattern is this? Greedy reach tracking, an implicit BFS. The tell is “minimum number of steps” on an array where each cell says how far you can go.
Approach
- Set
jumps = 0,end = 0(edge of the current window) andfar = 0(best reach seen). - Scan
ifrom 0 ton - 2. You stop before the last index because standing on it needs no further jump. - At each
i, updatefar = max(far, i + nums[i]). - If
i == end, the current window is exhausted: add one jump and setend = far. - Return
jumps.
Solution
def jump(nums):
jumps = end = far = 0
for i in range(len(nums) - 1): # never jump from the last index
far = max(far, i + nums[i]) # furthest reach from the current window
if i == end: # window exhausted: must take a jump
jumps += 1; end = far
return jumps
# jump([2,3,1,1,4]) -> 2Dry run
On nums = [2, 3, 1, 1, 4]:
i |
nums[i] |
far |
i == end? |
jumps |
end after |
|---|---|---|---|---|---|
| 0 | 2 | 2 | yes (end was 0) | 1 | 2 |
| 1 | 3 | 4 | no | 1 | 2 |
| 2 | 1 | 4 | yes | 2 | 4 |
| 3 | 1 | 4 | no | 2 | 4 |
The loop stops before index 4. The answer is 2.
Complexity
- Time: O(n). One pass, constant work per index.
- Space: O(1). Three integers.
Edge cases and pitfalls
- Single element (
[0]) returns 0: the loop range is empty. - Looping to
n - 1instead ofn - 2adds a spurious jump whenendlands exactly on the last index. - Greedily jumping to the furthest index from where you stand is wrong; the right move is counting windows, not picking the biggest jump.
- Unreachable end isn’t possible here, but in a variant you’d detect it when
far <= iat a window edge.
Related problems
- Jump Game (LeetCode 55): the yes/no version, tracking only the furthest reach.
- Partition Labels (LeetCode 763): the same “extend the far edge, close the window when you hit it” scan.
- Gas Station (LeetCode 134): another one-pass greedy with a running state that decides when to reset.
- 1.Assign Cookies (LeetCode 455)
- 2.Jump Game (LeetCode 55)
- 3.Jump Game II (LeetCode 45)
- 4.Gas Station (LeetCode 134)
- 5.Partition Labels (LeetCode 763)
- 6.Task Scheduler (LeetCode 621)
- 7.Hand of Straights (LeetCode 846)
- 8.Remove Covered Intervals (LeetCode 1288)
- 9.Valid Parenthesis String (LeetCode 678)
- 10.Merge Triplets to Form Target Triplet (LeetCode 1899)
- 11.Candy (LeetCode 135)