Go中无内置贪心函数,能否得最优解取决于“当前最优”定义是否正确;需满足贪心选择性质和最优子结构,典型可解问题有区间调度、分数背包、特定条件硬币找零,反例为整数背包问题0322。

Go 里没有内置的贪心算法函数,所有贪心逻辑都得自己写。能不能得到最优解,不取决于语言,而取决于你是否选对了“当前最优”的定义方式——错一步,后面全偏。
怎么判断一个问题是贪心可解的
不是所有优化问题都适合贪心。常见可解场景有三类:区间调度(如 0435. Non-overlapping Intervals)、分数背包(FractionalKnapsack)、硬币找零(仅当面额满足特定条件时)。关键看是否具备「贪心选择性质」和「最优子结构」。
典型反例是 0322. Coin Change(整数背包):用 [1,3,4] 换 6 元,贪心选 4+1+1=3 枚,但最优是 3+3=2 枚。这种情况下贪心失效,必须换 DP。
- 先查题干是否明确说“可以重复使用”“允许取部分物品”——这是分数背包的信号
- 看输入是否天然支持排序后单次扫描(比如所有区间都有
start/end字段) - 避免凭直觉认为“选最大/最小就一定对”,一定要验证局部最优是否真能推导出全局最优
排序是贪心最常踩的坑
绝大多数 Go 贪心实现依赖 sort.Slice 或自定义 sort.Interface,但排序规则一写错,结果就全错。比如活动安排问题,必须按 end 升序排;而重建队列(0406. Queue Reconstruction by Height)要先按身高降序、再按 k 值升序。
常见错误:
立即学习“go语言免费学习笔记(深入)”;
- 用
sort.Ints直接排二维切片——它只排第一维,没用 - 在
Less函数里漏掉相等情况的处理,导致排序不稳定 - 修改原切片同时又在循环中依赖索引位置,结果因排序后下标错位而越界或漏判
正确写法示例(区间结束时间升序):
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
边界判断比逻辑本身还重要
贪心过程通常是一次遍历,但起始点、终止条件、重叠判定稍有不慎就会漏解或多算。比如判断两个区间 [a,b] 和 [c,d] 是否重叠,不能只写 b > c,得考虑闭区间还是开区间——LeetCode 默认是闭区间,所以安全写法是 b 表示不重叠,否则就得用 <code>b >= c 判重叠。
- 空输入(
len(intervals) == 0)必须单独返回,别指望循环能兜住 - 单元素输入容易被忽略,比如只有一段区间时,是否要计为 1 个有效活动?要看题意
- 更新“当前最优基准”时(如记录上一个选中的
end),别在第一次迭代前就初始化成-1然后硬比较,应从第一个元素开始设初值
为什么你的贪心代码跑不过测试用例
很多失败不是算法错,而是 Go 类型和语义细节没对齐。例如:
- 用
int存时间戳但题目给的是float64区间,做比较时隐式转换出精度问题 - 在
for i := range items中修改i,结果下一轮i被 for 自动递增,跳过下一个元素 - 把“最多能选几个区间”误实现成“最少删几个区间”,方向反了
- 忘记对输入做深拷贝就直接排序——如果测试用例复用同一底层数组,后续 case 就会拿到已排序脏数据
真正难的不是写出贪心循环,而是确认你选的那个“当前最优”,在所有边界组合下都依然成立。


















