[Medium] 45. Jump Game II
You are given a 0-indexed array of integers nums of length n. You are initially positioned at nums[0].
Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at nums[i], you can jump to any nums[i + j] where:
0 <= j <= nums[i]andi + j < n
Return the minimum number of jumps to reach nums[n - 1]. The test cases are generated such that you can reach nums[n - 1].
Examples
Example 1:
Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [2,3,0,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
Jump 1 step from index 0 to 1, then 3 steps to the last index.
Constraints
1 <= nums.length <= 10^40 <= nums[i] <= 1000- It’s guaranteed that you can reach
nums[n - 1].
Thinking Process
- BFS-like Level Traversal: Each jump represents a “level” in BFS
- BFS visits nodes in non-decreasing distance from the source.
- Queue guarantees shortest path in unweighted graphs.
- Process level by level when counting layers or distances.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Queue BFS (this problem) | O(n) | O(n) | Shortest path in unweighted graphs |
| Multi-source BFS | O(n) | O(n) | Start from all sources simultaneously |
| 0-1 BFS / deque | O(n) | O(n) | Weights 0 or 1 |
| Level-order BFS | O(n) | O(w) | Process by depth/layer |
Solution
Time Complexity: O(n) - Single pass through the array
Space Complexity: O(1) - Only using constant extra space
This solution uses a greedy BFS-like approach, tracking the current end of the current jump level and the farthest reachable position.
Solution: Greedy with BFS Tracking
class Solution {
public:
int jump(vector<int>& nums) {
int rtn = 0, n = nums.size();
int curEnd = 0, curFar = 0;
for(int i = 0; i < n - 1; i++) {
curFar = max(curFar, i + nums[i]);
if(i == curEnd) {
rtn++;
curEnd = curFar;
}
}
return rtn;
}
};
Solution Explanation
Approach: Queue BFS (this problem)
Key idea: 1. BFS-like Level Traversal: Each jump represents a “level” in BFS
How the code works:
- BFS-like Level Traversal: Each jump represents a “level” in BFS
- BFS visits nodes in non-decreasing distance from the source.
- Queue guarantees shortest path in unweighted graphs.
- Process level by level when counting layers or distances.
Walkthrough — input nums = [2,3,1,1,4], expected output 2:
The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.
| Approach | Time | Space | Pros | Cons | |———-|——|——-|——|——| | Greedy BFS | O(n) | O(1) | Optimal, simple | Requires understanding | | Dynamic Programming | O(n²) | O(n) | Intuitive | Slower, more space | | Explicit BFS | O(n) | O(1) | Clear variable names | Slightly verbose |
Algorithm Breakdown
int jump(vector<int>& nums) {
int rtn = 0; // Number of jumps
int n = nums.size();
int curEnd = 0; // End of current jump level
int curFar = 0; // Farthest position reachable
// Don't need to process last index
for(int i = 0; i < n - 1; i++) {
// Update farthest reachable position
curFar = max(curFar, i + nums[i]);
// If we've reached the end of current level
if(i == curEnd) {
rtn++; // Make a jump
curEnd = curFar; // Update to next level boundary
}
}
return rtn;
}
Why This Works
BFS Analogy
Think of it as BFS levels:
- Level 0: Index 0 (starting position)
- Level 1: All indices reachable from level 0
- Level 2: All indices reachable from level 1
- And so on…
curEnd marks the boundary of the current level, and curFar tracks the boundary of the next level.
Greedy Optimality
At each level, we greedily extend to the farthest position because:
- If we can reach position
jinkjumps, we can reach any position≤ jinkjumps - Extending farthest gives us the most options for the next jump
- This minimizes the total number of jumps
Complexity
| Approach | Time | Space | Pros | Cons | |———-|——|——-|——|——| | Greedy BFS | O(n) | O(1) | Optimal, simple | Requires understanding | | Dynamic Programming | O(n²) | O(n) | Intuitive | Slower, more space | | Explicit BFS | O(n) | O(1) | Clear variable names | Slightly verbose |
Implementation Details
Why i < n - 1?
for(int i = 0; i < n - 1; i++)
We don’t need to process the last index because:
- If we reach
n - 1, we’re done (no need to jump from it) - The loop processes indices where we might need to make decisions
- This avoids unnecessary computation
curEnd and curFar Relationship
- curEnd: Boundary of current BFS level (where current jump can reach)
- curFar: Farthest position reachable from current level (boundary of next level)
- When
i == curEnd, we’ve explored all positions in current level, so we jump to next level
Greedy Choice Property
curFar = max(curFar, i + nums[i]);
This ensures we always know the farthest position reachable from the current level, allowing us to make the optimal greedy choice.
Common Mistakes
- Single element:
[0]→ return0(already at last index) - Can jump directly:
[3,1,1,1]→ return1(one jump from start) - Need multiple jumps:
[2,3,1,1,4]→ return2 -
Zeros in middle:
[2,0,1,1,4]→ still solvable (guaranteed by constraints) - Processing last index: Including
i < ninstead ofi < n - 1 - Wrong initialization: Not initializing
curEndandcurFarto 0 - Missing jump increment: Forgetting to increment
rtnwheni == curEnd - Wrong update order: Updating
curEndbefore checkingi == curEnd - Off-by-one errors: Incorrect boundary conditions
Optimization Tips
- Early Exit: Can add check if
curFar >= n - 1to exit early - Single Pass: The greedy approach already achieves optimal O(n) time
- Space Optimization: Already O(1) space, no further optimization needed
Related Problems
- 55. Jump Game - Check if can reach last index
- 1306. Jump Game III - Can jump backward/forward
- 1345. Jump Game IV - Can jump to same value indices
- 1696. Jump Game VI - Maximum score with sliding window
- 1871. Jump Game VII - Can only jump to ‘0’s
Real-World Applications
- Network Routing: Finding minimum hops in network
- Game Development: Pathfinding with jump mechanics
- Resource Allocation: Minimizing steps in resource distribution
- Algorithm Design: Understanding greedy optimization
Pattern Recognition
This problem demonstrates the “Greedy BFS” pattern:
1. Track current level boundary
2. Track next level boundary
3. When reaching current boundary, advance to next level
4. Always extend to farthest position
Similar problems:
- Minimum steps problems
- Level-order traversal variants
- Greedy optimization with boundaries
Why Greedy is Optimal
- Optimal Substructure: Minimum jumps to position
i+ optimal jump fromi= optimal solution - Greedy Choice: Extending farthest gives maximum future options
- No Future Dependencies: Decision at each level doesn’t depend on future levels
- Monotonicity: Once we can reach a position, we can always reach it (no need to reconsider)
Key Takeaways
- BFS-like Level Traversal: Each jump represents a “level” in BFS
- Greedy Choice: Always extend to the farthest reachable position
- curEnd Tracking: Marks the boundary of current jump level
- curFar Tracking: Tracks the farthest position reachable from current level
- Early Termination: Stop at
n - 1since we don’t need to jump from last index
References
- LC 45: Jump Game II on LeetCode
- LeetCode Discuss — LC 45: Jump Game II
- LeetCode Editorial (may require premium)