Max Howell 被 Google 拒绝了,你真的还敢轻视算法面试吗?

Homebrew 的作者 Max Howell 在 Google 面试时因为写不出反转二叉树而被拒。这个事件当年在程序员圈子里炸开了锅——一个全世界最流行的软件的作者,居然栽在一道算法题上。很多人替他不平,但《代码随想录》的作者 Carl 在书中一针见血地指出:算法面试之所以成为大厂的标配,不是因为面试官偷懒,而是因为它是短时间内考查程序员思维能力和代码功底最公平的方式。

"一个面试环节可能只有一个小时,面试官需要在短时间内快速考查一位面试者的编程水平……算法题目是短时间内考查面试者计算机思维和代码能力的最好的方式,算法问题在面试中可以将面试官对面试者的主观看法带来的影响降到最低。"

读完这段话我才意识到,吐槽算法面试容易,但要拿出一个更好的替代方案,几乎不可能。


这本书最核心的价值,是给了你一套"刷题导航"

市面上的算法书要么太厚(比如 CLRS 那本 1000 多页的巨著),要么太散(各种博客东一篇西一篇)。Carl 发现很多人在刷题时最痛苦的其实不是题目本身难,而是三个问题:不知道该从哪开始刷、找到的题要么太简单要么太难、没有靠谱的题解可以参考。这本书的解法不是再堆一本题目合集,而是给了你一套完整的刷题顺序——每一个专题内的题目由易到难编排,前面的题目为后面的做知识铺垫,环环相扣。

"很多人刷题的效率低,主要体现在以下三点:难以寻找适合自己的题目。找到了不合适现阶段做的题目,结果发现毫无头绪。没有全套的优质题解可以参考。"

这种设计理念让我想到了一句话:算法不是靠背的,是靠"喂"出来的——用对的顺序喂对的题。


读到"树层去重"和"树枝去重"的时候我停顿了很久

回溯算法里有一个经典的困惑:题目要求结果集合之间不能重复,但很多资料只说"要去重",从来没人讲清楚到底在哪个环节去重。Carl 在书中自创了两个词——"树层去重"和"树枝去重"。树层去重是在同一层递归中避免重复选择,树枝去重是在一条路径上避免重复使用同一个元素。这两个词一出来,整个回溯的去重逻辑瞬间清晰了。这就是真正理解一个算法的人和只会照本宣科的人之间的区别。

graph TD
  A[刷题三大痛点] --> B[不知从哪开始]
  A --> C[题目难度不合适]
  A --> D[没有好题解]
  B --> E[代码随想录的解法]
  E --> F[二叉树: 递归三部曲]
  E --> G[回溯: 回溯三部曲]
  E --> H[动规: 动规五部曲]
  F --> I[确定参数/返回值]
  F --> J[确定终止条件]
  F --> K[确定单层递归逻辑]
  H --> L[dp数组含义]
  H --> M[递推公式]
  H --> N[初始化/遍历/打印]

但全书最让我震惊的发现,是一个 O(n) 变成 O(n²) 的陷阱

书中举了一个让我后背发凉的例子:在一个数组中每隔一定间隔插入一个数字,你觉得时间复杂度是多少?大多数人会回答 O(n)。但如果你用 C++ 的 vector.insert() 来写,实际时间复杂度是 O(n²)——因为 insert 操作本身就是 O(n) 的,还要加上 vector 扩容时的全量复制。作者用这个例子说明了一个残酷的事实:不懂编程语言的底层机制,你写出来的算法可能比你以为的慢一百倍。

算法专题方法论名称核心步骤
二叉树递归三部曲确定参数和返回值类型 → 确定终止条件 → 确定单层递归的逻辑
回溯算法回溯三部曲回溯函数模板参数 → 终止条件 → 遍历搜索过程
动态规划动规五部曲确定dp数组含义 → 确定递推公式 → dp数组初始化 → 确定遍历顺序 → 举例推导dp数组

批判地说,这本书有一个明显的局限

全书统一使用 C++ 讲解,虽然作者在配套网站上提供了 Java、Python、Go、JavaScript 等多语言版本,但阅读过程中需要在书和网站之间来回切换,体验上有些割裂。另外,书中覆盖的题目数量有限(两百道左右),对于刷题量已经较大的读者来说,可能会觉得不够过瘾。但这不妨碍它作为一本优秀的算法面试入门教材——它的目标本来就不是面面俱到,而是帮你搭建一个清晰的知识框架。


延伸阅读

  • 《算法导论》(CLRS)—— 算法领域的圣经级教材,适合系统性地深入学习算法理论
  • 《编程珠玑》(Jon Bentley)—— 短小精悍,每一章都是一个算法思维的经典案例
  • 《剑指Offer》(何海涛)—— 另一本程序员面试刷题经典,可以和本书互补使用