Example 1
ready- Input
nums = [ 2, 3, 1, 1, 4 ]- Expected
true- Why
- jump to index 1, then reach the last index
A single zero can turn a promising route into a dead end. The real question is whether you ever have to land on it.
You're given an array nums. At index i, the value nums[i] is the maximum number of
positions you may jump forward from there. Starting at index 0, return true if some
sequence of jumps can reach the last index; otherwise return false.
A jump may be any length from 1 through the current maximum. You don't have to use the
full jump, and reaching the last index is enough — you never need to jump beyond it.
1 <= nums.length <= 10_0000 <= nums[i] <= 100_000Hints
Work backward and mark an index safe when it can jump to another safe index. This gives a direct solution, even if it checks many destinations repeatedly.
While scanning from the start, every reachable index may extend one shared frontier, the furthest index any jump sequence has reached so far.
If the scan arrives at index i but the frontier is smaller than i, no earlier
reachable position can land there. If the frontier reaches the last index, you're done.
Can you adapt the same frontier idea to count the minimum number of jumps when the last index is guaranteed to be reachable?
Visible cases
nums = [
2,
3,
1,
1,
4
]truenums = [
3,
2,
1,
0,
4
]falsenums = [
1,
1,
0
]trueInterview signal
You don't need to remember every route. You only need to know how far all routes together can reach.
Dynamic programming (DP) stores answers to smaller versions of a problem so you can
reuse them. Let reachable[i] say whether the last index can be reached from i. The
last index is already safe. Moving right to left, inspect every landing position allowed
by nums[i]; if any landing is safe, i is safe too.
def can_jump(nums: list[int]) -> bool:
n = len(nums)
reachable = [False] * n
reachable[-1] = True
for i in range(n - 2, -1, -1):
limit = min(n - 1, i + nums[i])
for landing in range(i + 1, limit + 1):
if reachable[landing]:
reachable[i] = True
break
return reachable[0]Time O(n²) in the worst case — many indices may inspect nearly the whole suffix. Space O(n) for the reachability table.
Scan only the positions already inside a reachable prefix. Each one offers a new right
endpoint, i + nums[i]; retain the largest endpoint offered so far.
def can_jump(nums: list[int]) -> bool:
furthest = 0
for i, jump_length in enumerate(nums):
if i > furthest:
return False
furthest = max(furthest, i + jump_length)
if furthest >= len(nums) - 1:
return True
return TrueThe exchange argument is a proof that swapping another choice for the greedy choice
can't hurt the final answer. After scanning through index i, imagine any collection of
jump sequences that reaches the scanned prefix. Exchange its remembered endpoint for the
furthest endpoint any of those sequences offers. Every nearer landing remains available
because jumps may stop short, while no competing choice unlocks an index beyond
furthest. Keeping only that frontier is therefore globally optimal. If i lies beyond
it, every possible route is stuck before i.
Time O(n) — each index is scanned at most once. Space O(1) — one frontier replaces the whole table.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
true