15% off all plans & roadmaps Use code
See plansEditorial
Core insight
Jump Game · Greedy Patterns
Core Insight for Jump Game
The key intuition that transitions us from a naive simulation to an optimal greedy solution is the realization that we do not need to track how we get to an index, nor do we need to track every reachable index. We only need to track the maximum reachable index (let's call it maxReach) from the starting point.
If we can reach index i, and nums[i] allows us to jump k steps, then we can inherently reach every index between i and i + k. Therefore, the set of reachable indices is always a contiguous range starting from 0.
As we iterate through the array, we update maxReach based on the jump power at the current position. The invariant is simple: as long as the current index i is less than or equal to maxReach, we are on a valid path. If i ever exceeds maxReach, it means the current index is disconnected from the start, and the end is unreachable.
Visual Description: Imagine a "frontier" line moving across the array. Initially, the frontier is at index 0. As you visit each index up to the frontier, the value at that index may push the frontier further to the right. If your iteration catches up to the frontier and the frontier does not move forward (because the jump value is 0), you are stuck. If the frontier reaches or passes the last index, you succeed.
Deep dive
Full breakdown
Full reasoning, pitfalls, and implementation flow
LeetCode 55: Jump Game Solution & Explanation
Problem Overview
TL;DR: The optimal solution uses a greedy approach to track the furthest reachable index (maxReach) as we iterate through the array; if the current index exceeds maxReach, the end is unreachable.
In the LeetCode 55 problem, commonly known as Jump Game, you are provided with an array of non-negative integers. You begin at the first index of the array. Each element in the array represents the maximum jump length available at that position. Your objective is to determine if it is possible to reach the last index of the array starting from the beginning.
This is a popular interview question that tests your ability to optimize decision-making processes from exponential or quadratic time down to linear time.
Brute Force Approach for Jump Game
The naive approach to solving the Jump Game involves exploring every possible jump combination to see if any path leads to the last index. This is typically implemented using recursion or backtracking. From the current index i, we try every jump length from 1 to nums[i] and recursively check if the destination is valid.
Pseudo-code:
function canReach(index):
if index == last_index:
return true
max_jump = nums[index]
for jump from 1 to max_jump:
if canReach(index + jump):
return true
return falseWhy it fails: The time complexity of this approach is exponential, specifically in the worst case (or depending on jump sizes). For an array of length (as per constraints), the recursion tree grows excessively large, resulting in a Time Limit Exceeded (TLE) error. The algorithm repeatedly recalculates reachability for the same indices without memorizing the results.
Algorithm Strategy: Greedy Patterns
- Initialize Variables: Maintain a variable
maxReachinitialized to 0. This represents the furthest index we can currently reach. - Iterate: Loop through the array using an index
i. - Check Constraints: Before processing index
i, check ifi > maxReach.- If true, it implies index
iis not reachable from the start. Returnfalse.
- If true, it implies index
- Update State: Update
maxReachto be the maximum of its current value andi + nums[i].maxReach = max(maxReach, i + nums[i])
- Early Exit: If
maxReachis greater than or equal to the last index (n - 1), returntrueimmediately. - Final Result: If the loop completes without returning
false, returntrue.
Execution Flow
Consider the input nums = [2, 3, 1, 1, 4]. Length is 5. Target index is 4.
- Start:
maxReach = 0. - i = 0:
- Is
0 > maxReach(0)? No. - Update
maxReach:max(0, 0 + 2) = 2. maxReachis not . Continue.
- Is
- i = 1:
- Is
1 > maxReach(2)? No. - Update
maxReach:max(2, 1 + 3) = 4. - Check:
maxReach(4) Target (4). - Return True.
- Is
Consider the input nums = [3, 2, 1, 0, 4]. Target index is 4.
- Start:
maxReach = 0. - i = 0:
maxReachbecomes0 + 3 = 3. - i = 1:
maxReachbecomesmax(3, 1 + 2) = 3. - i = 2:
maxReachbecomesmax(3, 2 + 1) = 3. - i = 3:
maxReachbecomesmax(3, 3 + 0) = 3. - i = 4:
- Is
4 > maxReach(3)? Yes. - We cannot reach index 4.
- Return False.
- Is
Proof of Correctness
The correctness relies on the "contiguous reachability" property. If we can reach index , we can reach all indices .
- Base Case: We start at index 0, so we can reach index 0.
- Inductive Step: Assume we can reach all indices up to
maxReach. For any validi(), the jumpnums[i]allows us to reachi + nums[i]. Since we can reachi, we can naturally reach any point betweeniandi + nums[i]. By taking the maximum of alli + nums[i], we extend the contiguous range of reachable indices to the newmaxReach. - Conclusion: If the loop finishes or
maxReachcovers the last index, a path exists. If the iteratorisurpassesmaxReach, there is a gap in reachability that cannot be bridged.
Pattern Reuse Notes
The Greedy - Jump Game Reachability/Minimization pattern applies to several other problems. Mastering this logic is crucial for interview preparation.
- LeetCode 45: Jump Game II: Instead of returning true/false, you must find the minimum number of jumps to reach the end. The pattern is similar but requires tracking the "current jump end" and "furthest reach" simultaneously.
Feynman coach · Before you peek at the code
Can you explain the core insight in your own words?
If you can explain it before reading code, you’re far more likely to recall it under interview pressure.
Reference Implementation
C++ Solution for LeetCode 55
1class Solution {
2public:
3 bool canJump(vector<int>& nums) {
4 int maxReach = 0;
5 int n = nums.size();
6
7 for (int i = 0; i < n; ++i) {
8 // If the current index is beyond our maximum reach,
9 // we cannot proceed further.
10 if (i > maxReach) {
11 return false;
12 }
13
14 // Update the furthest reachable index
15 maxReach = max(maxReach, i + nums[i]);
16
17 // Optimization: If we can already reach the end, return true
18 if (maxReach >= n - 1) {
19 return true;
20 }
21 }
22
23 return true;
24 }
25};Java Solution for LeetCode 55
1class Solution {
2 public boolean canJump(int[] nums) {
3 int maxReach = 0;
4 int n = nums.length;
5
6 for (int i = 0; i < n; i++) {
7 // If current index is not reachable, we are stuck
8 if (i > maxReach) {
9 return false;
10 }
11
12 // Update the maximum reach based on current position's jump power
13 maxReach = Math.max(maxReach, i + nums[i]);
14
15 // Early exit if we can reach the last index
16 if (maxReach >= n - 1) {
17 return true;
18 }
19 }
20
21 return true;
22 }
23}Python Solution for LeetCode 55
1class Solution:
2 def canJump(self, nums: List[int]) -> bool:
3 max_reach = 0
4 n = len(nums)
5
6 for i, jump in enumerate(nums):
7 # If current index is beyond reachable range
8 if i > max_reach:
9 return false
10
11 # Update the furthest point we can reach
12 max_reach = max(max_reach, i + jump)
13
14 # If we can reach the last index, return True immediately
15 if max_reach >= n - 1:
16 return True
17
18 return True