(LeetCode-Hot100)55. 跳跃游戏

问题简介

🔗 LeetCode 55. 跳跃游戏

题目描述

给定一个非负整数数组 nums,你最初位于数组的第一个下标。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。


示例说明

示例 1:

text 复制代码
输入: nums = [2,3,1,1,4]
输出: true
解释: 从下标 0 跳 1 步到下标 1,然后跳 3 步到达最后一个下标。

示例 2:

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

解题思路

📌 核心思想 :我们不需要知道具体怎么跳,只需要判断能否到达终点。因此,可以维护一个变量表示当前能到达的最远位置。


✅ 方法一:贪心算法(推荐)

步骤如下:

  1. 初始化 maxReach = 0,表示当前能到达的最远下标。
  2. 遍历数组(只需遍历到倒数第二个元素,因为最后一步不需要再跳):
    • 如果当前下标 i > maxReach,说明无法到达当前位置,直接返回 false
    • 否则,更新 maxReach = max(maxReach, i + nums[i])
  3. 遍历结束后,若 maxReach >= n - 1,则可以到达终点。

💡 为什么有效?

因为我们始终记录"能到达的最远位置",只要这个位置 ≥ 最后一个下标,就说明可达。


❌ 方法二:动态规划(不推荐,仅作对比)
  • 定义 dp[i] 表示是否能到达下标 i
  • 初始 dp[0] = true
  • 对每个 i,若 dp[i] == true,则将 i+1i+nums[i] 的位置都设为 true
  • 最终返回 dp[n-1]

⚠️ 缺点:时间复杂度 O(n²),在 LeetCode 上会超时或效率低。


✅ 方法三:反向遍历(另一种贪心)
  • 从后往前找,维护一个 lastPos = n - 1(目标位置)。
  • i + nums[i] >= lastPos,说明从 i 可以跳到 lastPos,更新 lastPos = i
  • 最终若 lastPos == 0,说明可以从起点跳到终点。

💡 这种方法逻辑清晰,但实际效率略低于正向贪心(因需完整遍历)。


代码实现

java 复制代码
// Java 实现 - 贪心(正向)
class Solution {
    public boolean canJump(int[] nums) {
        int maxReach = 0;
        int n = nums.length;
        
        for (int i = 0; i < n; i++) {
            if (i > maxReach) {
                return false;
            }
            maxReach = Math.max(maxReach, i + nums[i]);
            // 提前终止优化
            if (maxReach >= n - 1) {
                return true;
            }
        }
        return true;
    }
}
go 复制代码
// Go 实现 - 贪心(正向)
func canJump(nums []int) bool {
    maxReach := 0
    n := len(nums)
    
    for i := 0; i < n; i++ {
        if i > maxReach {
            return false
        }
        if i + nums[i] > maxReach {
            maxReach = i + nums[i]
        }
        // 提前终止
        if maxReach >= n - 1 {
            return true
        }
    }
    return true
}

💡 提示 :以上代码均采用正向贪心,并加入提前终止优化,效率最高。


示例演示

nums = [2,3,1,1,4] 为例:

i numsi maxReach(更新前) 是否 i > maxReach? 更新后 maxReach
0 2 0 max(0, 0+2)=2
1 3 2 max(2, 1+3)=4
2 1 4 4(不变)
... ... ... ... ...

✅ 在 i=1 时,maxReach = 4 >= 4(n-1),提前返回 true


答案有效性证明

📌 贪心选择性质

在每一步,我们都选择"能跳得最远"的策略,这不会导致错过可行解。因为如果存在一条路径能到达终点,那么必然存在某个时刻,我们的 maxReach 能覆盖终点。

📌 最优子结构

能否到达位置 i,只依赖于前面所有位置中能跳到 i 的最大能力。因此局部最优(最远可达)可推出全局最优(能否到终点)。

✅ 因此,贪心算法在此问题中是正确且完备的。


复杂度分析

方法 时间复杂度 空间复杂度 说明
贪心(正向) O(n) O(1) 一次遍历,常数空间
动态规划 O(n²) O(n) 每个位置可能更新多个状态
贪心(反向) O(n) O(1) 一次反向遍历

✅ 推荐使用正向贪心,简洁高效。


问题总结

  • 🔑 关键洞察:无需关心具体跳跃路径,只需关注"最远能到哪"。
  • 🧠 思维转变:从"如何跳" → "能不能到",简化问题。
  • 技巧 :提前终止(一旦 maxReach >= n-1 就返回)可提升性能。
  • 📌 适用场景:此类"可达性"问题常可用贪心解决,尤其是当"局部最优能保证全局最优"时。

💡 延伸思考 :本题变种 LeetCode 45. 跳跃游戏 II 要求最少跳跃次数,同样可用贪心解决,但需记录"跳跃次数"和"当前边界"。

github地址: https://github.com/swf2020/LeetCode-Hot100-Solutions

相关推荐
Jerry1 小时前
LeetCode 28. 找出字符串中第一个匹配项的下标
算法
Jerry3 小时前
LeetCode 459. 重复的子字符串
算法
闲猫5 小时前
Spring AI 对接Deepseek ChatModel 聊天对话
java·前端·spring
海石5 小时前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石5 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
自信的未来7 小时前
JSON 工具|Web Worker 工程化打包 + 语法自动修复 + 多语言代码生成实战
java·前端·json
Brookty7 小时前
【JavaEE】线程安全(一).4:写块串行保安全、CAS
java·开发语言·java-ee·多线程·线程安全
技术小甜甜7 小时前
[软件商业化] Steam 游戏更新怎么发公告?预告、上传新包和正式升级说明的顺序怎么安排?
游戏·steam·独立游戏·steamworks·游戏更新·软件商业化
Jerry7 小时前
LeetCode 151. 反转字符串中的单词
算法