Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

从暴力搜索到更好算法

复习

  • 回溯与搜索树:枚举所有可能
  • 动态规划:用缓存消除重复子问题
  • 贪心选择:每步只选当前最优

TL;DR

  • 暴力搜索枚举所有可能,简单但慢
  • 记忆化/动态规划消除重复子问题
  • 贪心在能成立时更快,但可能出错
  • 同一个问题可以有多种解法,取决于利用了多少问题结构

正文

  一路走来,我们认识了贪心、动态规划、回溯等好几种“设计算法的方法”。这一章把它们串成一条线,看看同一类问题,是怎样一步步变得更好的

一条从慢到快的谱系

  面对一个问题,可以有不同层次的解法:

  1. 暴力枚举:把所有可能都试一遍。简单、正确,但往往指数级,只能处理很小规模
  2. 回溯 + 剪枝:仍然枚举,但提前砍掉没希望的分支,比纯暴力高效
  3. 记忆化 / 动态规划:发现子问题重复,缓存结果,把指数级降为多项式级
  4. 贪心:如果问题结构足够好,每步选最优即可,通常最快

  每一步的进步,来自对问题结构利用得更多:从“什么都不利用”,到“利用约束剪枝”,到“利用重叠子问题”,再到“利用最优子结构”。

但更快不等于更通用

  这里有个关键提醒:越靠后的方法,适用范围往往越窄,正确性也越需要论证。

  • 暴力枚举几乎万能,只是慢
  • 动态规划要求重叠子问题与最优子结构
  • 贪心最快,但经常不成立——上一章就专门讲了怎么证明或推翻它

  所以,并不是“越快越好”。选哪种方法,取决于问题本身具备什么性质,以及你是否能证明它的正确性。一个用错前提的贪心,比老老实实的暴力枚举更糟,因为它可能悄悄给出错误答案。

选择,才是核心

  这条谱系真正想教给我们的,不是四种具体方法,而是一种判断力:

  面对新问题,先问——它有没有重复子问题?有没有最优子结构?能不能用约束把搜索剪小?贪心的直觉能不能被证明?

  问清楚了,方法自然就浮现出来。这也正好引向整个部分的最后一章:没有万能的数据结构和算法,只有合适的取舍。

思考题 1

  从暴力搜索到动态规划,改进的关键是什么?

思考题 2

  既然贪心通常更快,为什么不能什么问题都用贪心?

小结

知识点

  • 暴力枚举、回溯剪枝、动态规划、贪心构成一个谱系
  • 进步源自对问题结构的更多利用
  • 更快的方法通常适用范围更窄、更需论证
  • 选择方法要先判断问题的性质

参考资料

  1. Wikipedia(zh):算法设计:常见算法设计范式
  2. Wikipedia(zh):动态规划:利用重叠子问题的改进方法

思考题答案(仅供参考)

思考题 1

  关键在于发现并利用“重叠子问题”:暴力与回溯会反复计算同样的子问题,而动态规划把每个子问题的结果缓存起来、只算一次,从而把指数级的重复计算降为多项式级。

思考题 2

  因为贪心并不总是正确。它只在“局部最优能导向全局最优”的问题上成立,而很多问题不具备这种性质。贸然使用贪心可能给出错误答案,因此必须先用证明或反例确认它的正确性。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪