D

当前:LC55 · 跳跃游戏 · 首次出现于 Day 40 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC55

跳跃游戏:别急着跳,先看安全边界能不能覆盖终点

贪心 · 可达性

这题不是问 「怎么跳最优」,而是问 「有没有可能到终点」。 所以我们不真的去选每一步落点,只维护一个数字: 当前安全边界 reach

输入 · nums
23114
起点 index 0 终点 lastIndex = 4
是否可达终点
true
reach 已覆盖 lastIndex
时间 O(n) · 一次遍历空间 O(1) · 一个变量 reach关键不变量:reach 单调不减区分 LC45:那题问最少几步

错误思路 · 枚举所有跳法

从 0 出发 nums[0]=2,可以选择跳到 1、2、… 2。 每个落点又分叉出新的选择,路径数指数级膨胀。 但题目只问能不能到, 不问怎么到, 这些路径细节全部不需要保留。

?1
?2
?3
?4
↑ 想象每格都要分叉——指数级。

正确思路 · 只维护安全边界 reach

把 [0..reach] 想成已经亮起来的安全区。 扫描到 i 时,如果 i 在安全区内, 就用 nums[i] 试着把右边界推得更远。 只看最大 reach,路径细节全丢掉。

[0safe zone · reach 不断向右扩reach]
↑ 只需一个变量 reach,O(1) 状态。
初始化Step 1 / 7

浮空岛主舞台 · 安全区扩张

扫描 i = · reach = 0
reach = 0
START
i=02
nums[0]
i=13
nums[1]
i=21
nums[2]
i=31
nums[3]
GOAL
i=44
nums[4]
初始化:Pathfinder 站在 0 号岛,reach = 0。安全区 [0..0] 只覆盖出发岛,还没向右扩张。
绿色安全区 · [0..reach]蓝色扫描柱 · 当前 i黄色光束 · 候选 i+nums[i]红色断崖 · i > reach绿色旗帜 · 终点 lastIndex

Go 解法 · 与状态同步

高亮行:2
1func canJump(nums []int) bool {
2 reach := 0
3 for i, jump := range nums {
4 if i > reach {
5 return false
6 }
7 reach = max(reach, i+jump)
8 }
9 return true
10}

蓝色 = 初始化 · 绿色 = 扩张 reach · 金色 = 保持 reach · 红色 = 失败分支。

状态面板 · 这一帧的全部状态

当前 i
nums[i]
oldReach (before)
0
candidate = i + nums[i]
newReach = max(old, cand)
0
当前结论
reach = 0 · 安全区只含起点

为什么 reach 这套就够 · 四点说明

  • reach 的含义
    从 0 出发,经过已扫描的可达位置后,能到达的最远下标。它不是“某条具体路径终点”,而是“所有可行路径的右端最大值”。
  • 如果 i ≤ reach,可以扩张
    说明 i 在安全区内,从某条路径可以到达 i。再用 nums[i] 试 i + nums[i],谁大留谁,安全边界继续向右推。
  • 如果 i > reach,立即 false
    前面所有可达位置最远只能推到 reach,连脚下 i 都没法触达,后面的位置只会更远,更不可能处理。直接 return false。
  • 为什么只留最大 reach 就够
    LC55 只问能不能到终点,不问最少几步、不问具体路径。更大的可达边界永远不会让答案变差,所以贪心取 max 是安全的。

执行轨迹 · reach 是怎么一步步变化的

lastIndex = 4 · 点击行跳转
Stepinums[i]i > reach?candidatereach (before → after)动作
000初始化
102no202扩张 reach
213no424扩张 reach
321no344reach 保持
431no444reach 保持
544no848扩张 reach
688覆盖终点 · 成功

面试 30 秒答题模板

这题只问能不能从 0 跳到最后一格,所以我做 一次遍历, 维护一个变量 reach:扫描每个下标 i 时先判断 i > reach,如果是说明这个位置根本到不了,直接返回 false; 否则用 reach = max(reach, i + nums[i]) 把安全边界向右推。扫描结束没失败,就一定能到终点,返回 true。 时间 O(n)、 空间 O(1)。 正确性来自:reach 始终等于已扫描前缀内可达的最远下标, i 在安全区内才能继续扩张,否则前面所有可达位置都到不了 i,整个数组也就到不了终点。

常见误区 · 别再翻车

  • 以为必须找出具体跳法
    LC55 只问可达性,不问具体路径,更不问最少跳几次。维护一个 reach 数字就够,不需要回溯、不需要记录从哪跳到哪。
  • 看到 nums[i] = 0 就判失败
    0 只意味着「从这块岛跳不出去」,但只要前面别的可达岛已经把 reach 越过这块岛,整体仍然有救。看的是 reach,不是某一格的值。
  • 和 LC45 混在一起
    LC55 是「能不能到」,返回 bool;LC45 是「最少跳几步到」,返回 int,需要维护当前层右边界 + 下一层右边界,比 LC55 多一层状态。
  • 只看成功样例
    失败样例 [3,2,1,0,4] 才暴露关键:所有可达岛把 reach 推到 3 就上不去了,i=4 时 i > reach 触发断崖。没看失败样例就没真正理解 reach。