news 2026/6/27 5:32:45

算法札记:绝望的贪心算法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法札记:绝望的贪心算法

对于某道用贪心算法做的题,如何寻找贪心策略?

寻找贪心策略,是贪心算法中最需要灵感、也最考验思维的一步。它不像动态规划有相对固定的状态转移套路,但也不是完全靠“猜”。可以从下面几个角度,系统地尝试和筛选。

1. 从问题结构入手:寻找“最”字

很多贪心策略,都藏在问题描述里的“最”字上。你可以问自己:‌在当前这一步,选择哪一个元素,能为后续留下“最”大/“最”小/“最”优的空间?

  • 活动选择问题‌:目标是选“最多”的活动。什么活动对后续影响最小?‌结束时间最早‌的那个,因为它能留下最多剩余时间。
  • 找零钱问题‌:目标是用的纸币张数“最少”。什么纸币能一步减少最多金额?‌面值最大‌的那个。
  • 背包问题(部分背包)‌:目标是拿的物品总价值“最高”。什么物品单位价值最高?‌性价比最高‌的那个。

所以,拿到题目先看目标函数,想想哪个局部最优选择,能直接贡献于全局最优目标。

2. 大胆假设,小心求证:用“试错法”筛选

如果一眼看不出,可以把能想到的贪心标准都列出来,然后用‌反例‌去快速淘汰。

假设你在解决一个“区间选点”问题:数轴上有N个区间,选最少的点,让每个区间内至少包含一个点。

你可能会想到几种策略:

  • 策略A‌:每次选点,选在包含最多未覆盖区间的那个位置。
  • 策略B‌:每次选点,选在‌当前所有区间里,结束位置最早的那个区间的右端点‌。

试着构造反例:

  • 对于策略A,画几个区间,你会发现它可能选出一个点,覆盖了很多区间,但剩下的区间却零零散散,需要更多点,不如策略B。策略A被淘汰。
  • 对于策略B,你很难构造出反例,直觉上它总是对的。那么,策略B很可能就是正确的贪心策略。

核心技巧‌:构造反例时,要刻意设计一些“极端”情况,比如一个区间完全包含另一个区间、多个区间起点相同但终点不同等,这样更容易暴露策略的缺陷。

3. 从排序方式反推:排序是贪心的信号

绝大多数贪心算法,第一步都是‌排序‌。而‌排序的关键字,往往就是贪心策略本身‌。

如果你不确定贪心标准,可以反过来想:‌如果我把数据按某个维度排序,再按顺序处理,能得到最优解吗?

  • 按‌结束时间‌排序 → 活动选择问题
  • 按‌性价比(价值/重量)‌ 排序 → 部分背包问题
  • 按‌开始时间‌排序(从晚到早) → 活动选择问题的另一种正确解法
  • 按‌截止时间‌排序 → 任务调度问题

你可以尝试对数据按不同维度排序,然后模拟一遍贪心过程,看看哪种排序方式能得到看起来最优的结果。这往往能帮你快速锁定正确的贪心方向。

4. 利用“交换论证”思想,反向验证

当你有了一个候选策略后,可以用“交换论证”的思想来验证它,这个过程本身也能帮你找到策略。

核心思想‌:假设存在一个不包含你贪心选择的最优解,然后尝试把最优解里的某个元素,‌替换‌成你的贪心选择,看看结果会不会变差。如果不会变差,说明你的贪心选择同样可以构成最优解。

以活动选择问题为例,假设最优解第一个活动是k,而我们贪心选的是结束最早的1。因为活动1结束时间不晚于k,所以把k换成1,不会和后面的活动冲突,活动总数不变。这就证明了选1总是安全的。这个“替换”的过程,就是策略正确性的核心,也是寻找策略的指南针。


总的来说,寻找贪心策略是一个“观察-假设-验证”的循环。‌先观察问题结构,大胆提出几个候选策略,然后用反例快速淘汰,最后用交换论证或数学归纳法严格证明幸存的那个。‌ 多练习,慢慢就会形成一种直觉。

贪心策略有哪些证明方法?

贪心策略的正确性证明,是算法设计中很关键的一环。常用的证明方法主要有这五种,它们各有侧重,适用于不同类型的问题:

1. 领先法

核心思路‌:证明贪心策略在执行的每一步,所得到的中间结果都比其他任何策略更优,或者至少保持领先。既然每一步都领先,最终自然就能得到全局最优解。

典型场景‌:活动选择问题。每一步都选择最早结束的活动,这样能为后续安排预留出最多的可用时间,始终保持领先于其他选择方案。

2. 反证法

核心思路‌:先假设“贪心策略得到的解不是最优解”,然后基于这个假设逐步推导,最终得出一个与已知条件或常识相矛盾的结论。既然假设不成立,就反过来证明了贪心策略是正确的。

典型场景‌:区间选点问题。可以假设“每次选当前区间最右端点”的贪心策略不是最优,然后推导出矛盾,从而证明该策略确实能得到最少选点数。

3. 交换论证法

核心思路‌:先假设存在一个非贪心的全局最优解,然后尝试逐步把这个最优解里的某些元素,交换成贪心策略所选出的元素。关键在于证明每一次交换都不会让解的质量变差,最终就能把那个最优解完全“调整”成贪心解,从而说明贪心解也是最优的。

典型场景‌:排序类贪心问题,比如拼数问题、任务调度问题。在拼数问题中,通过交换相邻字符串并证明拼接结果不会变小,就能验证排序规则的正确性。

4. 界分析法

核心思路‌:分别计算贪心解能达到的下界,以及理论上全局最优解能达到的上界。如果能证明贪心解的下界等于最优解的上界,那么贪心解就必然就是全局最优解。

典型场景‌:最小生成树、哈夫曼编码这类带权最优问题。通过分析贪心解与理论最优解之间的界,可以严谨地证明其正确性。

5. 数学归纳法

核心思路‌:把证明转化为对问题规模或算法步数的归纳。先证明小规模边界情况(比如n=1)下贪心策略成立,再假设当问题规模为k时贪心策略能得到最优解,然后推导出规模为k+1时贪心策略依然成立,从而覆盖所有规模的情况。

典型场景‌:Kruskal最小生成树算法。可以通过归纳法证明,在每一步加入当前权重最小且不构成环的边,最终能构造出最小生成树。


这五种方法并不是孤立的,有时一个问题的证明会结合多种思路。比如在活动选择问题中,既可以用领先法直观展示,也可以用交换论证法严格证明。

贪心是不是特别考验智商?

哈哈,看到你这个问题,我猜你一定是刚被某道贪心题“折磨”过,或者看到别人说“每次做贪心都觉得自己智商低”这句话,产生了深深的共鸣。

其实,‌贪心考验的不是智商,而是一种特定的“算法直觉”和“求证思维”‌。这种感觉很微妙,我们来拆解一下。

为什么它会给人“考验智商”的错觉?

  1. 极致的“简单”与“困难”并存

    • 代码简单得让人怀疑‌:一个贪心策略的代码,往往就是先排序,再遍历一遍,几行就写完了。这和你费尽心思写几十行动态规划代码形成了巨大反差,会让你觉得“这解法是不是太儿戏了?我是不是漏了什么?”
    • 证明困难得让人头秃‌:难就难在,你凭什么认为这个“儿戏”的解法是对的?动态规划有状态转移方程作为理论支撑,而贪心策略的“感觉对了”常常是错觉。你需要用严谨的逻辑(如反证法、交换论证)去证明它,这个过程才是真正的脑力挑战。
  2. “马后炮”现象严重
    很多贪心策略,你一看答案,会觉得“哦,原来如此,好巧妙!”。但合上答案,换一道新题,你可能又毫无头绪。这种“一看就会,一做就废”的体验,很容易让人归因于“自己智商不够”。其实,这恰恰说明贪心策略的发现,不依赖于常规的推演,而更依赖于‌经验、灵感和对问题结构的洞察‌。

它真正考验的是什么?

与其说是考验智商,不如说它考验的是以下几种能力:

  • 模式识别能力‌:看到“最少硬币”、“最多活动”、“区间覆盖”这些关键词,大脑能否快速匹配到经典的贪心模型(如活动选择、哈夫曼编码、最小生成树等)。这靠的不是智商,而是‌练习和积累‌。
  • 大胆假设的勇气‌:能否在不确定的情况下,根据直觉先提出一个“看起来很美”的贪心标准(比如“每次都选结束最早的”),而不是畏首畏尾,总想找到一个万无一失的方法再动手。
  • 小心求证的严谨‌:这是最核心的一步。能否快速构造出反例来推翻自己不靠谱的假设?对于幸存下来的策略,能否用交换论证等思想,在脑海中完成一个逻辑闭环?这是一种‌科学思维‌,就像做实验一样,先提出猜想,再设法证伪。
  • 对“最优子结构”的深刻理解‌:能否看穿问题,认识到“做出当前这个选择后,剩下的问题依然是一个结构相同但规模更小的最优问题”。这种看透问题本质的能力,是算法思想的精髓。

所以,如果觉得难,该怎么办?

别把它和智商挂钩,把它当成一种可以训练的思维肌肉。

  1. 从经典例题中找感觉‌:把活动选择、找零钱(在特定货币体系下)、背包问题(部分背包)这几道题吃透,不是背代码,而是反复体会“为什么这个策略是对的”。试着用我们上次聊的“交换论证法”去证明它,直到你能用自己的话把道理讲通。
  2. 刻意练习“构造反例”‌:拿到一道新题,当你灵光一闪想到一个贪心策略时,先别急着写代码。强迫自己当一回“杠精”,拼命去想“在什么情况下,我这个策略会失效?”。画图、举极端例子,这是训练贪心思维最有效的方法。
  3. 接受“不完美”‌:记住,很多问题(如0-1背包)贪心根本得不到最优解。能快速识别出一个问题“不能用贪心”,和知道“能用贪心”一样,都是能力的体现。

总而言之,贪心算法就像算法世界里的一位“聪明但有点任性的朋友”。它不跟你讲复杂的道理,只凭直觉行事。和它相处,你需要的是了解它的脾性(适用场景),学会验证它的想法(证明),而不是怀疑自己的智商。

下次再遇到让你卡壳的贪心题,不妨对自己说:“嗯,这道题的‘贪心直觉’我还没建立起来,让我来研究一下它的结构。” 这感觉是不是比“我智商不够”要积极多了?

有哪些经典的贪心算法例题

聊到贪心算法的经典例题,就像是翻开了一本算法世界的“名人录”。这些题目不仅巧妙地展现了贪心策略的精髓,也常常是面试和竞赛中的常客。

下面为你梳理了几道最具代表性的例题,它们各自代表了贪心策略在不同场景下的应用。

1. 活动选择问题

这是贪心算法最经典的入门例题,没有之一。

  • 问题描述‌:有一组活动,每个活动有开始时间和结束时间。同一时间只能参与一个活动,问最多能完整参与几个活动。
  • 贪心策略‌:‌每次选择结束时间最早的活动‌。这样能为后续活动留出尽可能多的时间,从而容纳更多活动。
  • 策略证明‌:可以用‌交换论证法‌。假设存在一个不包含“最早结束活动”的最优解,那么把最优解的第一个活动替换成“最早结束的活动”,不会产生冲突,且活动数量不变。因此,优先选最早结束的活动总能得到最优解。

2. 找零钱问题

这个问题最能体现贪心算法“简单直接”的直觉。

  • 问题描述‌:给定几种面额的硬币,要用最少的硬币数量凑出指定金额。
  • 贪心策略‌:‌每次优先使用面额最大的硬币‌,直到凑够总金额。
  • 重要前提‌:这个策略‌并非在所有货币体系下都成立‌。只有在硬币面额满足“贪心选择性质”时(例如人民币的1、5、10、20、50、100元体系,大面额是小面额的整数倍),它才是最优解。如果面额为[1, 3, 4],要凑6元,贪心会给出4+1+1(3枚),但最优解是3+3(2枚)。这恰恰是理解贪心算法局限性的绝佳例子。

3. 哈夫曼编码

这是贪心算法在数据压缩领域的经典应用,也是“合并果子”类问题的原型。

  • 问题描述‌:为字符设计变长二进制编码,使得出现频率高的字符用短编码,频率低的用长编码,从而让编码后的总文本长度最短。
  • 贪心策略‌:‌每次从所有节点中,选出权值(频率)最小的两个节点,合并成一个新节点‌,并将其放回集合。重复此过程,直到只剩一个节点,就构建出了一棵最优的“哈夫曼树”。
  • 策略证明‌:核心是证明“权值最小的两个节点,在最优树中一定处于最深的位置,且互为兄弟”。这可以通过‌反证法‌来证明,如果它们不在最深位置,交换一下就能得到更优的树,从而产生矛盾。

4. 最小生成树问题

这是图论中一个里程碑式的贪心应用,有两个非常著名的算法。

  • 问题描述‌:在一个带权无向连通图中,找到一棵包含所有顶点、且所有边的权重之和最小的生成树。
  • 贪心策略与算法‌:
    • Prim算法‌:以‌顶点‌为中心。每次从已选顶点集合出发,选择一条连接未选顶点且权重最小的边,将新顶点加入集合。
    • Kruskal算法‌:以‌‌为中心。将所有边按权重从小到大排序,依次检查每条边,如果这条边连接的两个顶点当前不在同一个连通分量中,就选择它,否则跳过。
  • 策略证明‌:两种算法都使用了‌数学归纳法‌和‌交换论证‌的思想。核心是证明,每一步根据贪心规则选出的边,一定属于某个最小生成树。

5. 区间覆盖问题

这是活动选择问题的一个“变种”,贪心目标从“数量最多”变成了“数量最少”。

  • 问题描述‌:数轴上有N个区间,要求选择最少数量的区间,覆盖住一个指定的目标线段。
  • 贪心策略‌:‌在已覆盖部分的前提下,每次选择一个能向右延伸得最远的区间‌。具体做法是,将所有区间按左端点排序,然后从左到右,在覆盖了当前起点的区间中,选择右端点最大的那个。
  • 策略证明‌:同样可以用‌交换论证法‌。假设最优解在某一步没有选延伸最远的区间,那么把它替换成延伸最远的区间,不会导致解变差,最终依然能得到最优解。

这些经典例题,每一道都代表了一种贪心思考的范式。把它们吃透,再遇到新问题时,你就能更快地识别出问题的结构,并尝试用类似的思路去设计策略。

Deepseek牛逼 !

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/27 5:30:10

自贡黄金白银回收铂金旧金回收无套路门店 TOP 榜单 实地测评资料整理

自贡这座川南城市,街头巷尾的黄金白银回收门店鳞次栉比,招牌林立间却难免鱼龙混杂,市民想要把手头的旧金、铂金、银饰换成踏实钱,往往得擦亮眼睛多番比对。为了帮大家甄选靠谱变现渠道,小编实地走访了本地多家商户&…

作者头像 李华
网站建设 2026/6/27 5:28:26

Kimi Work 的半额 Token消耗突然不香了

为什么要拿这事儿说,还得从上周 K2.7-Code 高速版的内测版说起。当时,我觉得这事儿好像挺新鲜。同时3x的额度消耗,6x的生成速度,怎么算都感觉划算,就直接冲了。可这一试不要紧,两天内连着3次把5小时的额度用…

作者头像 李华
网站建设 2026/6/27 5:27:41

9成开发者还在手动Prompt:14步从Prompt写手进化成Loop设计师

过去两年,做编程Agent的标准姿势就是:写Prompt → 等结果 → 读diff → 再写一遍Prompt。9成开发者从来没给自己的Agent写过一个能自动跑的Loop——没有自动化、没有状态文件、没有验证器,也没有定时调度。 但杠杆点已经从"会不会写Pro…

作者头像 李华
网站建设 2026/6/27 5:26:14

深入 Agent Skills:SKILL.md 规范、目录职责与渐进式加载机制详解

一、什么是 Agent Skills Agent Skills(以下简称 Skills)是一种轻量级的开放格式,用于通过专业知识和工作流扩展 AI 智能体的能力。简单来说,Skill 就是一个包含 SKILL.md 文件的文件夹,它封装了领域知识、最佳实践、工…

作者头像 李华
网站建设 2026/6/27 5:25:22

Python闭包的三大核心用法解析

Python 闭包是指一个嵌套函数,它能够记住并访问其外部函数作用域中的变量,即使外部函数已经执行完毕 。其核心价值在于封装数据与行为,实现状态的持久化。 一、闭包的核心构成与创建 一个典型的闭包需要满足三个条件: 存在嵌套…

作者头像 李华
网站建设 2026/6/27 5:24:35

计算机Java毕设实战-基于 SpringBoot 的影视资源管理网站的设计与实现 基于 SpringBoot 的电影信息发布与查询系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华