Problem Statement
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]
.
LeetCode:
Constraints
1 <= nums.length <= 10^4
0 <= nums[i] <= 1000
It's guaranteed 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
Different Approaches
1️⃣ Brute Force (Recursion) (TLE)
Since we are given different choices at each index (i.e., we can jump from 1 to nums[i]
steps), and we want to explore all possible paths to find the minimum number of jumps, recursion is a natural fit.
Recursion is especially useful when choices or decisions need to be explored one by one, like in this case.
Approach:
- Base Case:
- If you're at or beyond the last index (i >= n - 1), you’ve reached the goal, so return 0 jumps needed.
- Recursive Case:
- Try every possible jump length from 1 to nums[i], and:
- Recursively solve for the next position (i + step)
- Add 1 jump for the current move
- Take the minimum among all options
- Return the minimum jumps from the current index to the end.
Code:
class Solution {
public:
int solve(vector<int>& nums, int i) {
// Base case: reached or passed last index
if (i >= nums.size() - 1) {
return 0;
}
int mini = 1e9; // large number
for (int step = 1; step <= nums[i]; step++) {
int jumps = 1 + solve(nums, i + step); // take the jump
mini = min(mini, jumps); // track the minimum
}
return mini;
}
int jump(vector<int>& nums) {
return solve(nums, 0); // start from index 0
}
};
Complexity Analysis:
- Time Complexity:
O(n^n)
In the worst case because from each index you may try all
nums[i]
paths, leading to an explosion of recursive calls.For example: If nums = [3, 3, 3, 3, 3], then: From index 0 → try jumps to index 1, 2, 3 From index 1 → again try jumps to next 3 indices, and so on. So, it’s a tree with branching factor ~3, depth n, hence exponential.
- Space Complexity:
O(n)
- For the recursion stack in the worst case (when you jump just 1 step each time).
2️⃣ Memoization
If we notice we have the overlapping subproblems in the recursive approach. So we can memoize it.
Code:
class Solution {
public:
int solve(vector<int>& nums, int i, vector<int>& dp) {
if (i >= nums.size() - 1) {
return 0;
}
if (dp[i] != -1) return dp[i]; // return cached result
int mini = 1e9;
for (int step = 1; step <= nums[i]; step++) {
int next = i + step;
if (next < nums.size()) {
int jumps = 1 + solve(nums, next, dp);
mini = min(mini, jumps);
}
}
return dp[i] = mini; // store and return
}
int jump(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, -1);
return solve(nums, 0, dp);
}
};
Complexity Analysis:
- Time Complexity:
O(n^2)
- For each index
i
, we compute the result once. - For each
i
, we may explore up tonums[i]
steps – worst case up ton
→ total ~O(n^2)
- For each index
- Space Complexity:
O(n)
- For the dp array and recursion stack.
3️⃣ Greedy Approach (Optimal)
Intuition:
- You’re at position i, and nums[i] tells you how far you can jump forward.
- The goal is to reach the last index using the minimum number of jumps.
- Instead of trying all paths (like recursion/DP), we scan the array in one pass and keep track of:
- How far we can go in the current jump range.
- When we exhaust that range, we jump and start a new range.
- It’s like layered BFS — at each level, you jump to the farthest node in that layer.
Approach:
- Start from index 0.
- Keep extending the farthest index you can reach in the current level.
- When you reach the end of the current jump (curEnd), you must jump and move to the next level (update curEnd = farthest).
- Repeat until you reach or pass the last index.
Code:
class Solution {
public:
int jump(vector<int>& nums) {
int jumps = 0; // Total number of jumps made
int curEnd = 0; // End of the current jump range
int farthest = 0; // Farthest index reachable so far
// We go only till the second last index
// because once we reach the last index, we don't need to jump anymore
for (int i = 0; i < nums.size() - 1; i++) {
// Update the farthest reachable index from this point
farthest = max(farthest, i + nums[i]);
// If we've reached the end of the current range,
// we need to make a jump and update the current range
if (i == curEnd) {
jumps++; // Take the jump
curEnd = farthest; // Update the current range
}
}
return jumps;
}
};
Complexity Analysis:
- Time Complexity:
O(n)
- We loop through the array once, updating variables – no nested loops or recursion.
- Space Complexity:
O(1)
- We use only constant extra space:
jums
,currEnd
,farthest
.
- We use only constant extra space: