我最喜欢用来问候选人的编码题

一篇广为讨论的博客文章,讲述了一个“最喜欢”的编程面试题——从两天的网页日志中找出“忠实客户”——引发了关于面试究竟该衡量什么的争论。评论者围绕题目陈述中的歧义、坚持避免 O(n²) 解法的必要性,以及与其优化内存内算法,不如直接使用 SQL 或 shell 工具是否更现实展开讨论。许多人认为这道题是在间接考察数据结构和沟通能力;也有人批评它过于做作,更偏爱擅长白板题的人,而不是那些能构建可维护、面向业务系统的人。

题目中的歧义与“陷阱感”

  • 许多人认为“忠实客户”这个需求(尤其是“至少两个不同页面”)定义不充分,或在逻辑上存在歧义。
  • 有些人认为这反映了现实世界的产品需求,并测试候选人识别歧义、提出澄清问题的能力。
  • 也有人觉得这不公平,像是在“读心”,尤其是在压力很大的面试中,候选人可能会担心提问会被扣分。
  • 还有人担心,面试官会高估自己已经多么清楚地传达了“请提问”。

这个问题真正测试的是什么

  • 支持者说它测试的是:
    • 识别糟糕的渐进复杂度(拒绝朴素的 O(n²))。
    • 使用基本数据结构(map/set)以及时间–空间权衡。
    • 推理大数据和约束条件的能力。
  • 批评者说,它主要奖励的是 LeetCode 式的模式匹配和 Big-O 讨论,而不是真正的现实技能,比如理解需求、系统设计或与相关方协作。
  • 还有人指出,最优的内存内解法很脆弱,并且与“恰好两天”强耦合,削弱了可扩展性。

替代的解法风格(SQL、shell、工具)

  • 许多人会用 shell 管道(sort/uniq/grep/awk)或一个小型 SQLite/数据库查询来解决,尤其是在一次性的业务报表场景里。
  • 争论点:
    • 支持 DB/shell:实现最快,更容易调整需求,借助外部排序/索引处理大数据。
    • 支持“20 行代码”:依赖最少;更聚焦算法理解。
  • 有人指出,这个问题本质上就是一个关系连接;数据库执行计划(hash join、merge join)与提出的 CS 方案是对应的。

性能 vs 实用性

  • 对“没有伟大的工程师会满足于 O(n²)”这句话存在强烈分歧。
    • 一方认为:二次方算法是危险的陷阱;更好的方案通常同样简单,而且应该是本能反应。
    • 另一方认为:对于一次性任务或小数据集,开发者时间和简单性比渐进复杂度更重要;过早优化很常见。
  • 还有几个人指出,聪明的微优化(只存 2 个页面、提前退出等)会增加复杂度,并降低对不断演化指标的灵活性。

面试设计、偏见与候选人体验

  • 有人称赞这个问题简单、直观,甚至适合资深工程师;也有人把这种算法现场编码描述为无聊、没有灵魂,甚至“去人性化”。
  • 另一个担忧是,这种形式会筛选出:
    • 能在高压、带有对抗感的测试中保持状态的人。
    • 专门训练过类似题目的人。
  • 也有人主张采用更协作的、类似结对编程的练习,或更小、更贴近现实的任务(例如 CLI 应用),作为衡量日常效率和团队协作的更好信号。