二刷 LeetCode:两道经典贪心题复盘

目录

[一、LeetCode 45. 跳跃游戏 II](#一、LeetCode 45. 跳跃游戏 II)

题目回顾

核心思路(正向贪心)

[Java 实现代码](#Java 实现代码)

二刷反思

[二、LeetCode 763. 划分字母区间](#二、LeetCode 763. 划分字母区间)

题目回顾

[核心思路(两次遍历 + 边界扩展)](#核心思路(两次遍历 + 边界扩展))

[Java 实现代码](#Java 实现代码)

二刷反思

三、贪心算法的通用复盘


二刷贪心算法专题,把两道经典中等题「跳跃游戏 II」和「划分字母区间」重新啃了一遍。比起第一次的懵懵懂懂,这次明显对贪心的核心思想有了更透彻的理解,也想把复盘整理成博客,帮自己沉淀下来,也给同在路上的伙伴们一点参考。


一、LeetCode 45. 跳跃游戏 II

题目回顾

给定一个非负整数数组 nums,你最初位于数组的第一个下标。数组中的每个元素代表你在该位置可以跳跃的最大长度。你的目标是使用最少的跳跃次数到达数组的最后一个位置。题目保证你一定可以到达终点。

核心思路(正向贪心)

这道题的贪心核心是:不需要知道每一步具体跳到哪个位置,只需要维护当前跳跃能覆盖的区间,在区间内找到下一步能跳得最远的位置,以此减少跳跃次数

  • 维护三个变量:
    • step:记录跳跃次数,初始为 0
    • currentEnd:当前这一跳能到达的最远边界
    • maxReach:在当前区间内遍历,更新能到达的下一个最远边界
  • 遍历数组(注意不需要遍历到最后一个元素):
    1. 更新 maxReach = max(maxReach, i + nums[i])
    2. 当遍历到 currentEnd 时,说明当前区间已经遍历完毕,必须进行下一次跳跃:step++,同时更新 currentEnd = maxReach
    3. 如果 currentEnd 已经能到达终点,直接提前结束

Java 实现代码

java

运行

复制代码
public int jump(int[] nums) {
    int n = nums.length;
    if (n <= 1) return 0;
    int step = 0;
    int currentEnd = 0;
    int maxReach = 0;
    for (int i = 0; i < n - 1; i++) {
        maxReach = Math.max(maxReach, i + nums[i]);
        if (i == currentEnd) {
            step++;
            currentEnd = maxReach;
            if (currentEnd >= n - 1) break;
        }
    }
    return step;
}

二刷反思

  • 第一次写的时候,很容易陷入「找具体路径」的误区,想着用动态规划记录每个位置的最少跳跃次数,结果写出来的代码又复杂又低效。
  • 这次才真正理解:贪心的精髓是放弃局部最优路径的细节,只保留全局最优的边界信息。时间复杂度直接从 O (n²) 降到了 O (n),空间复杂度 O (1),完美符合面试官的期望。
  • 易错点:循环条件是 i < n - 1,因为最后一个位置不需要再跳一次,否则会多算一次跳跃次数。

二、LeetCode 763. 划分字母区间

题目回顾

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

核心思路(两次遍历 + 边界扩展)

这道题的贪心核心是:先预处理每个字符的最后出现位置,再遍历字符串动态扩展当前片段的边界,当遍历到边界时,就是一个合法的片段

  1. 预处理:第一次遍历字符串,用数组 last[26] 记录每个小写字母最后一次出现的下标
  2. 贪心划分:第二次遍历字符串,维护当前片段的起点 start 和终点 end
    • 对于每个字符 c,更新 end = max(end, last[c - 'a'])
    • i == end 时,说明当前片段已经包含了所有出现过的字符,记录片段长度 end - start + 1,并更新 start = i + 1

Java 实现代码

java

运行

复制代码
public List<Integer> partitionLabels(String s) {
    List<Integer> res = new ArrayList<>();
    int[] last = new int[26];
    int n = s.length();
    // 预处理每个字符的最后出现位置
    for (int i = 0; i < n; i++) {
        last[s.charAt(i) - 'a'] = i;
    }
    int start = 0;
    int end = 0;
    for (int i = 0; i < n; i++) {
        end = Math.max(end, last[s.charAt(i) - 'a']);
        if (i == end) {
            res.add(end - start + 1);
            start = i + 1;
        }
    }
    return res;
}

二刷反思

  • 第一次做的时候,想到了用哈希表记录最后位置,但对「动态扩展边界」的理解不够深,差点写了区间合并的复杂逻辑。
  • 这次才明白:贪心的关键是,当前片段的边界由已出现字符的最远位置决定,不需要额外处理区间合并,遍历过程中自然就能划分出所有合法片段。
  • 易错点:边界更新时,要一直取当前字符的最远位置,而不是只更新一次,否则会漏掉后面出现的字符。

三、贪心算法的通用复盘

这两道题看似场景不同,但底层的贪心思想高度一致:

  1. 放弃局部细节,聚焦全局最优:不纠结每一步的具体选择,只维护能影响后续决策的关键边界信息
  2. 预处理 + 单次遍历:先通过一次遍历拿到关键信息(比如最远位置、最大边界),再用一次遍历完成贪心决策,时间复杂度稳定在 O (n)
  3. 边界意识:两道题都对边界的处理有严格要求,比如跳跃游戏的循环终止条件、划分字母区间的片段终点判断,边界错一步,结果就会出错。
相关推荐
顺顺 尼1 小时前
程序地址空间和进程的一些操作
算法
Java成神之路-2 小时前
【LeetCode 刷题笔记】35. 搜索插入位置 | 二分查找经典入门题
算法·leetcode
计算机魔术师2 小时前
【职场观察 | 技术人处境】五一假期结束,职场两边同时加速——“简历热“和“优化潮“背后的结构性逻辑
人工智能·面试·职场和发展·cot 推理·技术人求职·ai替代逻辑
MediaTea12 小时前
AI 术语通俗词典:C4.5 算法
人工智能·算法
Navigator_Z12 小时前
LeetCode //C - 1033. Moving Stones Until Consecutive
c语言·算法·leetcode
WBluuue12 小时前
数据结构与算法:莫队(一):普通莫队与带修莫队
c++·算法
风筝在晴天搁浅13 小时前
n个六面的骰子,扔一次之后和为k的概率是多少?
算法
MATLAB代码顾问14 小时前
Python实现蜂群算法优化TSP问题
开发语言·python·算法
代码飞天14 小时前
机器学习算法和函数整理——助力快速查阅
人工智能·算法·机器学习