【中等】55. 跳跃游戏

0 阅读3分钟

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

示例 1:

输入: nums = [2,3,1,1,4]
输出: true
解释: 可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入: nums = [3,2,1,0,4]
输出: false
解释: 无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

提示:

  • 1 <= nums.length <= 104
  • 0 <= nums[i] <= 105

1. 生活案例:荒岛求生桥

想象你正在参加一个荒岛求生节目。你面前有一座由很多腐朽木板组成的桥,每一块木板 nums[i] 的数字代表: “如果你踩在这块板上,由于它的承重和弹性,你最远能向前跨几块板。”

  • 你的恐惧:有些木板的数字是 0。如果你落在那块板上,而你又没有余力跨过去,你就被困在桥中心了(掉进海里)。
  • 你的策略:你不需要计算跳多少次,你只需要在往前走的每一步,都不断确认: “我目前最远能跨到的那个安全点,是不是已经覆盖了终点?”

2. 代码解析与“生活化”注释

这段代码展示了如何用一个不断更新的“能量条”(farthest)来判断生死。

JavaScript

/**
 * @param {number[]} nums - 每一块木板能支撑你向前跨的最大距离
 * @return {boolean} - 是否能成功到达最后一块板
 */
var canJump = function(nums) {
    let farthest = 0; // 你目前“眼力+体力”能达到的最远位置
    let n = nums.length;

    // 每一块木板我们都去踩一下,看看能不能增加我们的“航程”
    for (let i = 0; i < n; i++) {
        // 生活化解释:
        // 如果你当前的脚步 i 已经超过了你之前能达到的最远距离 farthest
        // 说明你踩到了空处,或者被困死在了之前的 0 刻度上,任务失败!
        if (i > farthest) return false;

        // 尝试更新你的“航程纪录”:
        // 当前位置 i + 这一站能提供的弹跳力 nums[i]
        // 看看是不是比之前的最远纪录还要远
        farthest = Math.max(farthest, i + nums[i]);

        // 只要这个纪录已经超过或等于了终点下标 (n-1)
        // 恭喜你,你已经稳了,直接返回成功!
        if (farthest >= n - 1) return true;
    }

    // 走完所有路还没达到终点(理论上上面那个 return 会先触发)
    return false;
};

3. 为什么代码这样写?(贪心逻辑对比)

  1. 与跳跃游戏 II 的区别

    • 跳跃游戏 II(第 45 题):必须要等到当前这步走完了(i == end),才不得不增加步数。
    • 跳跃游戏 I(第 55 题):只要有一个瞬间发现 farthest 够得着终点,就可以提前交卷。
  2. 核心预警系统if (i > farthest) 是这个算法的灵魂。它就像是你的脚下突然一空:如果你走到了一个连之前最远跳跃都够不到的地方,那就说明前面的路存在死胡同。