(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 nums[i] 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

相关推荐
近津薪荼2 小时前
优选算法——前缀和(7):连续数组
算法
知识即是力量ol2 小时前
Java 虚拟机:JVM篇
java·jvm·八股
快乐zbc2 小时前
苍穹外卖 - 菜品起售/停售复习笔记
java·笔记
ArturiaZ2 小时前
【day29】
数据结构·c++·算法
MoonOutCloudBack2 小时前
VeRL 框架下 RL 微调 DeepSeek-7B,比较 PPO / GRPO 脚本的参数差异
人工智能·深度学习·算法·语言模型·自然语言处理
Cosmoshhhyyy2 小时前
《Effective Java》解读第41条:用标记接口定义类型
java·开发语言
_F_y3 小时前
二叉树中的深搜
算法
Anastasiozzzz3 小时前
深入浅出:理解控制反转 (IoC) 与 Spring 的核心实现
java·后端·spring
前路不黑暗@3 小时前
Java项目:Java脚手架项目的 B 端用户服务(十四)
android·java·开发语言·spring boot·笔记·学习·spring cloud