在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

跳跃游戏(LeetCode #55)

数组 nums[i] 表示从索引 i 最多向前跳多远,问题是能否到达最后索引。贪心只维护最远可达边界 reach,从左到右扫描,时间 O(n)、空间 O(1)。输入为非负跳跃长度。

从可达位置 i,可以跳 1 到 nums[i] 的任意距离,不是必须跳最大值。因此可达索引始终是从 0 开始的连续区间,没有内部空洞,只需保存右边界。逐落点 DP 或一般的显式图搜索要处理更多候选,最坏 O(n²);无记忆的试跳还可能重复大量路径。

跳跃游戏如何工作

每个索引执行两项,顺序不能交换。

先检查:若 i > reach,返回 False。扫描已经越过可达前沿。此时所有可能作为起跳点的较早位置都处理过,它们共同能达到的最远处仍是 reach。缺口后方再大的值也无法被使用,因为无法先站到那里。

再更新:reach = max(reach, i + nums[i])。已知 i 可达,它提供从 i 之后到 i + nums[i] 的连续落点,因此可以扩展已有连续区间。

算法不保存一条具体路线,也不模拟每次落到哪里。只求是否可达时,连续性让一个右边界足够。若规则改为必须跳精确距离,或部分位置禁止落脚,可达集合可能有洞,就不能直接复用这项压缩,应使用能表示实际可达状态的方法。

先更新再检查会让不可达位置也贡献跳跃。因为 nums[i] 非负,更新后一定有 reach ≥ i,检查再也无法失败,错误地接受所有输入。

循环完成则每个索引都通过检查,末位也可达,返回 True。

逐步演示

默认 nums = [2, 3, 1, 0, 4],用于说明零不一定阻断路径。

  1. i = 0:0 ≤ 0,通过。可跳到 1、2,reach = max(0, 0 + 2) = 2。
  2. i = 1:1 ≤ 2,通过。reach = max(2, 1 + 3) = 4,已覆盖末位,但本课继续扫描展示后续状态。
  3. i = 2:通过,2 + 1 = 3 没超过 4,前沿不变。
  4. i = 3:值为零,max(4, 3 + 0) = 4。零不扩展边界,但 3 本就在可达范围内,不导致失败。
  5. i = 4:4 ≤ 4,已到末位。更新甚至把 reach 推到 8;它是能力上界,可以超过数组。循环结束,返回 True。

切换 Every path funnels 的 [3, 2, 1, 0, 4]:0 最远到 3,1 的 1 + 2 = 3、2 的 2 + 1 = 3 都不能扩展。索引 3 的零也无贡献。到 i = 4,4 > 3,返回 False。末位的 4 不可达,不能帮助自己。

画布绿色轨道表示 reach,橙弧表示各格提供的最远跳跃。只有弧越过前沿,轨道才延伸。第一次扩展时,先展示所有允许落点,再把新区间与旧轨道合并,证明可达集合连续。失败预设中,三条最远弧落在同一处,轨道停止,红色虚线标出缺口。

时间与空间复杂度

方法时间空间
贪心扫描O(n)O(1)
逐位置 DPO(n²)O(n)

每个索引只检查并更新一次。可在 reach ≥ n − 1 时提前返回 True,但不改变最坏界。动画继续走完,是为了让默认零元素在已经可达的范围内被处理。

边界情况

  • 单元素,包括 [0]:已经位于末位,无需跳跃,返回 True。
  • 开头为零且还有后续:如 [0, 3],reach 停在 0,i = 1 立即失败。
  • 超过末尾:默认 n = 5、reach = 8,无需截断;循环只访问有效索引。
  • 缺口位置:首次失败必在 reach + 1,更早索引都位于前沿内。

常见错误

  • 见零就失败。 只有它让前沿停住、且后面仍有目标时才会阻断;默认有零也成功。
  • 先更新再检查。 不可达格会错误地扩大前沿,让检查永远通过。
  • 每次都跳最大值。 [2, 3, 0, 1, 4] 若从 0 直接跳两格会落到零,但先跳一格到值 3 就能到末位,正确答案为 True。
  • 为是否可达保存所有落点关系。 一般 BFS 能算对,但显式展开边最坏 O(n²);本题的“最多”规则已经让一个前沿足够。
  • 依赖最后一格的数值。 目标是到达它,不是从它再跳;它再大也不能弥补前方缺口。