55. Jump Game
On LeetCode ->Problem¶
Given an array nums, where nums[i] is the farthest you can jump from index i, start at index 0 and return whether you can reach the last index.
Example:
nums = [3,2,1,0,4] -> false
0 can reach up to index 3, but index 3 has value 0, so index 4 is unreachable
Key trick¶
Track the farthest index reachable while scanning left to right.
- If you reach an index beyond that farthest reachable position, you are stuck.
- If the farthest reachable position ever reaches or passes the last index, return
true.
Trap¶
- Exploring all jumps with DFS/BFS causes many repeated states and can time out.
- Thinking you must choose exact jumps is misleading; only the farthest reachable boundary matters.
- Forgetting that landing on a
0is fine if you can already jump past it.
Why is it interesting?¶
It looks like DP or graph search, but the best solution is a simple greedy invariant.
- You reduce many possible paths into one state: current farthest reachable index.
- It is a good test of recognizing when reachability beats path enumeration.
Python solution¶
class Solution:
def canJump(self, nums: list[int]) -> bool:
# farthest index we can reach so far
farthest = 0
last = len(nums) - 1
for i, jump in enumerate(nums):
# if current index is unreachable, we are stuck
if i > farthest:
return False
# extend the reachable range
farthest = max(farthest, i + jump)
# early exit if last index is already reachable
if farthest >= last:
return True
return True
Comment on my solution¶
Your solution times out because it explores too many duplicate states.
- From one index, you push many next indices.
- Those indices can be reached again from other paths.
- Without a visited set, the search grows explosively.
Even with a visited set, DFS is still worse than the greedy solution here.
- You do not need to explore paths.
- You only need the maximum reachable index at each step.
Also, this part does unnecessary work:
- Trying every jump length is the core inefficiency.
- The greedy insight avoids that entire loop.
If you wanted to keep a graph-style approach, you would at least need visited tracking:
But for interviews, the greedy solution is the right answer with \(O(n)\) time and \(O(1)\) space.
## Solution
# Implemented after reading AI comments
class Solution:
def canJump(self, nums: list[int]) -> bool:
# [2,3,1,1,4] -> True
# [3,2,1,0,4] -> False
max_idx = 0 # maximum idx in nums that can't be reach so far
for i in range(len(nums)):
if i > max_idx:
return False
max_idx = max(max_idx, i + nums[i])
if len(nums) - 1 <= max_idx:
return True
# Time Limit Exceeded (79 / 178 testcases passed)
class Solution:
def canJump(self, nums: list[int]) -> bool:
# [2,3,1,1,4] -> True
# [3,2,1,0,4] -> False
# - problem part of DP section but it seems that
# DFS + backtracking could work
# - What is the minimal state to keep track
# - maybe just use stack with (pos, jumps)
# - check if any jump from pos gets you to last index
# - if not but pos after jump in nums range push it on the stack
# - I think I just describe DFS
stack = [(0, nums[0])] # (pos, jumps)
while stack:
pos, jumps = stack.pop()
for jump in range(jumps + 1):
new_pos = pos + jump
if new_pos == len(nums) - 1:
return True
if new_pos != pos and new_pos < len(nums):
stack.append((new_pos, nums[new_pos]))
return False
Solution().canJump([2,3,1,1,4]) # True
Solution().canJump([3,2,1,0,4]) # False
Solution().canJump([2,5,0,0]) # True