给你一个非负整数数组 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 <= 1040 <= 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. 为什么代码这样写?(贪心逻辑对比)
-
与跳跃游戏 II 的区别:
- 跳跃游戏 II(第 45 题):必须要等到当前这步走完了(
i == end),才不得不增加步数。 - 跳跃游戏 I(第 55 题):只要有一个瞬间发现
farthest够得着终点,就可以提前交卷。
- 跳跃游戏 II(第 45 题):必须要等到当前这步走完了(
-
核心预警系统:
if (i > farthest)是这个算法的灵魂。它就像是你的脚下突然一空:如果你走到了一个连之前最远跳跃都够不到的地方,那就说明前面的路存在死胡同。