【贪心算法】LC 55.跳跃游戏

文章目录

前言

本专栏文章为《LeetCode 热题 100》的刷题题解,相关内容如有侵权,立即删除。

一、题目

1、原题链接

55. 跳跃游戏

2、题目描述

二、个人思路整理

1、思路分析

核心思路:维护最远可达位置

  1. 核心观察:

    • 如果你能到达某个下标 i i i,那么从起点到 i i i 之间的所有位置你都能到达。
    • 在下标 i i i 时,你能到达的最远位置为 i + nums i i + \text{nums}i i+numsi。
    • 因此,我们只需要遍历数组,动态更新全局最远可达下标 max_reach。
  2. 状态转移与边界:

    • 初始状态:max_reach = 0。
    • 遍历每个下标 i i i:
      • 不可达判断:如果当前下标 i > max_reach i > \text{max\_reach} i>max_reach,说明前面的跳跃无论如何都够不到当前位置,后续也绝不可能到达,直接返回 false。
      • 更新覆盖范围:更新 max_reach = max(max_reach, i + nums[i])。
      • 提前终止(剪枝):如果此时 max_reach >= n - 1,说明已经可以到达或超过最后一个下标,直接返回 true。
    • 如果能顺利遍历结束,说明可以到达终点,返回 true。

2、解题代码

cpp 复制代码
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        int max_reach = 0;   // 记录当前跳跃到达的最远下标

        for (int i = 0; i < n; i++) {
            // 如果当前位置已经超过了之前能到达的最远距离,说明中间断档,无法到达此处
            if (i > max_reach) {
                return false;
            }

            // 贪心更新当前能够覆盖的最远下标:当前下标 + 该处最大跳跃步数
            max_reach = max(max_reach, i + nums[i]);

            // 剪枝优化: 如果最远可达位置已经覆盖或超过了终点下标,直接返回成功
            if (max_reach >= n - 1) {
                return true;
            }
        }

        return true;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),只需线性遍历一次数组。
  • 空间复杂度: O ( 1 ) O(1) O(1),仅需常数级别的变量维护状态。

三、知识风暴

贪心算法(Greedy Algorithm) 是本题的核心算法思想。它通过每一步都做出当前看起来最优的选择,来逐步逼近全局最优解。对于跳跃游戏而言,我们不需要回溯所有可能的跳跃路径,只需在遍历过程中动态维护「当前能到达的最远位置」,即可判断能否抵达终点。理解贪心策略的正确性与边界处理,对掌握本题至关重要。

算法核心思想:

  • 局部最优推导全局最优 :在每个下标 i i i,我们只关心「从当前位置能跳到的最远位置」 i + nums i i + \text{nums}i i+numsi,并不断更新全局最远可达下标 max_reach。只要 max_reach 能覆盖到终点,就一定存在一条可行路径。
  • 不可达的判定 :如果遍历到某个下标 i i i 时,发现 i > max_reach i > \text{max\_reach} i>max_reach,说明前面的所有跳跃都无法触及当前位置,中间出现了「断档」,后续也绝不可能到达,直接返回 false。
  • 与动态规划的区别:动态规划需要记录每个位置是否可达,并可能回溯多条路径;而贪心只维护一个最远可达边界,无需额外数组,空间复杂度更低。

常见对比:贪心 vs 动态规划

  • 贪心算法 :时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)。只维护最远可达位置,思路简洁、效率最高,是本题的最优解。
  • 动态规划 :时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n ) O(n) O(n)。需要记录每个下标是否可达,并逐一判断从前面的哪些位置能跳到当前位置,适合需要统计路径数量或具体路径的场景。
  • 共同点:两者都能判断能否到达终点。区别在于贪心只关心「最远能到哪」,而动态规划关心「每个位置是否可达」。

"贪心"设计思想:

  • 核心思想 :利用「可达区间是连续的」这一性质------如果你能到达下标 i i i,那么起点到 i i i 之间的所有位置都能到达。因此只需维护一个不断右移的右边界 max_reach,无需关心区间内部的具体跳法。
  • 与本题的联系 :跳跃游戏只要求判断「能否到达终点」,不要求给出具体跳跃路径。因此我们无需记录每一步怎么跳,只需保证 max_reach 始终覆盖当前遍历到的下标即可。
  • 注意事项 :max_reach 的更新必须取「当前最远」与「从 i i i 出发能到的最远位置」的较大值,即 max_reach = max(max_reach, i + nums[i]),不能直接覆盖为 i + nums[i],否则可能丢失之前位置带来的更远覆盖。

使用要点:

  • 循环遍历 :用 for (int i = 0; i < n; i++) 顺序遍历每个下标,在循环内先判断是否可达,再更新最远覆盖。
  • 不可达判断 :if (i > max_reach) return false; 必须放在更新之前,因为当前位置不可达时,后续位置更不可能到达。
  • 剪枝优化 :每次更新后判断 if (max_reach >= n - 1) return true;,一旦覆盖终点即可提前结束,无需遍历完整个数组。
  • 结果返回 :若循环正常结束(未提前返回),说明所有下标都在可达范围内,返回 true。

算法变体与扩展:

  • 跳跃游戏(LeetCode 55):本题,贪心维护最远可达位置的标准应用。
  • 跳跃游戏 II(LeetCode 45):在保证能到达终点的前提下,求最少跳跃次数。需要额外维护「当前步的覆盖边界」与「下一步的最远覆盖」,是贪心的进阶应用。
  • 跳跃游戏 III(LeetCode 1306) :从起点出发,每次只能跳到 i + nums[i] 或 i - nums[i],且不能越界。由于跳跃方向不唯一,贪心失效,需改用 BFS 或 DFS 搜索。
  • 跳跃游戏 IV(LeetCode 1345):数组中相同值的下标可以互相跳跃,求最少步数。需要结合哈希表分组 + BFS 求解,是图论建模的进阶应用。

相关 LeetCode 例题:

相关推荐
ofoxcoding1 小时前
Jev 模型评测深度解析:核心得分、能力局限与最佳适用任务场景
人工智能·算法·机器学习·ai
Evand J1 小时前
【MATLAB例程】三维A*路径规划与TOA-AOA-TDOA融合定位算法。附下载链接
数据库·算法·matlab
liangshanbo12151 小时前
面试题:游戏、直播为什么常用 UDP?KCP 是什么?为什么比 TCP 更适合低延迟场景?
tcp/ip·游戏·udp
Doubbbbbbble云1 小时前
图算法中的剪枝技术与启发式优化分析4
算法·机器学习·剪枝
鶴哥只手遮天1 小时前
CFL3D深度解析:NASA经典CFD求解器的架构、算法与工程实践
算法
维克兜率天1 小时前
【维克】价差交易实战:配对交易的核心参数设置
大数据·笔记·算法·量化
dtq04241 小时前
数据结构 - 树的概念
c语言·数据结构·学习·算法
晒太羊的猫1 小时前
hot100多维动态规划刷题
算法·动态规划
勤劳X码农1 小时前
2026年游戏解说AI配音软件怎么选?
人工智能·游戏