当最弱的 AI 都能一次通过算法面试,我们还能用什么筛选程序员?

2026-05-14 21 预计阅读时间:1 分钟
来源:oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:10 分钟

Databricks 研究工程师 Yuchen Jin 在 X 上写了一段话,48 小时内浏览量冲到 46.8 万:"AI 终于杀死了 LeetCode 面试。过去十年,科技公司让每个工程师刷同样的算法题,证明自己能徒手反转二叉树。而今天,最弱智的 AI 模型进去就能一次性完成整个面试。"

这不是情绪化的吐槽,而是事实陈述。LeetCode 风格的算法面试,作为硅谷十年来的标准筛选工具,正在被大语言模型从根上瓦解。

一道题的死与生

"反转二叉树"之所以成为符号,源于 2015 年 Homebrew 作者 Max Howell 发的一条推:Google 拒绝了他,理由是他不会在白板上反转二叉树——而他写出了 Mac 上最流行的包管理器。这条推本身就在质疑算法面试的有效性,只是当时没有替代方案。

现在替代方案来了,不是更好的面试题,而是 AI 直接把题面拆了。

LeetCode 热题 100、剑指 Offer、企业高频题库——这些题的核心特征是:输入明确、输出确定、解法有限。这恰好是大语言模型最擅长的领域。模型不需要"理解"二叉树,它只需要见过足够多的反转实现,就能在推理时拼出正确代码。

AI 做题的实测表现

OpenAI 的 o3 模型在 Codeforces 竞赛题上达到 ELO 2027,相当于人类顶尖选手水平。更日常的场景里,GPT-4o 和 Claude 3.5 Sonnet 对 LeetCode 中等难度题的一次通过率已经超过 80%,困难题也在 50% 以上。

这不是"辅助编程",而是直接生成完整解法。面试者只需要把题面粘贴进去,拿到答案,稍作格式调整后提交。在线面试场景下,这个过程可以在 30 秒内完成。

下面用一个最小示例来演示这件事——调用 LLM API 解决一道经典中等难度题:

import openai

# LeetCode 102: 二叉树的层序遍历
# 题面描述(直接粘贴)
problem = """
给定二叉树的根节点 root,返回其节点值的层序遍历。
(即逐层地,从左到右访问所有节点)。

示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:
输入:root = [1]
输出:[[1]]

示例 3:
输入:root = []
输出:[]

请用 Python 实现,函数签名为 def levelOrder(root: Optional[TreeNode]) -> List[List[int]]
"""

client = openai.OpenAI()  # 需设置 OPENAI_API_KEY 环境变量

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "你是一个算法竞赛选手,直接输出可运行的 Python 代码,不要解释。"},
        {"role": "user", "content": problem},
    ],
    temperature=0.0,  # 低温度保证输出稳定
)

print(response.choices[0].message.content)

运行这段代码,你会拿到一份几乎可以直接提交的答案——BFS 用队列,时间复杂度 O(n),空间复杂度 O(n),标准解法。换一道题,换一个模型,结果大同小异。

关键点不是 AI 写的代码有多优雅,而是它写得太快、太稳了。 面试官花 45 分钟评估的信号,AI 在 30 秒内就能伪造。

面试信号被噪声淹没

算法面试的本质是信号提取:从候选人的解题过程中提取"逻辑清晰、代码扎实、能处理边界"这些信号。当 AI 可以一键生成完整解法,这些信号就变成了噪声——你无法分辨答案是来自候选人的大脑还是来自模型的推理。

更深层的问题是:这些信号本身的价值也在缩水。十年前,能徒手写出红黑树插入说明候选人底层功底扎实;今天,这项技能在日常开发中几乎不被使用。LLM 和 IDE 的补全功能已经覆盖了大部分常规编码场景。

那还面什么?

信号提取的目标没变——找到能胜任工程工作的人——但提取手段必须换。几个正在被验证的方向:

1. 系统设计 + 真实约束

不是画架构图,而是给一个有真实约束的问题:现有系统每天处理 2 亿请求,p99 是 300ms,现在要加一个新特征,延迟预算只有 50ms,怎么做?这种问题没有标准答案,AI 也无法直接生成——因为约束来自具体业务上下文。

2. 改代码而非写代码

给候选人一段有 bug 的生产代码,要求定位并修复。AI 可以生成新代码,但在理解他人代码、追踪隐含依赖、在既有架构中做最小改动方面,目前表现远不如人类。

3. 协作式面试

两人结对完成一个任务,面试官观察沟通方式、任务拆解、冲突处理。AI 无法模拟人际协作中的模糊性和谈判过程。

4. 带上下文的编码

给一个真实 repo 的片段,要求在现有测试框架下实现一个功能。需要理解项目结构、命名风格、测试约定——这些上下文 AI 很难从零拼出。

下面是一个"改代码而非写代码"的面试题示例,展示这类题目为什么对 AI 更难:

# 原始代码:一个有 bug 的缓存实现
class LRUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.cache = {}        # key -> value
        self.order = []        # 访问顺序列表

    def get(self, key: int) -> int:
        if key in self.cache:
            self.order.remove(key)     # BUG: O(n) 操作
            self.order.append(key)
            return self.cache[key]
        return -1

    def put(self, key: int, value: int) -> None:
        if key in self.cache:
            self.order.remove(key)     # BUG: 同上
        elif len(self.cache) >= self.capacity:
            oldest = self.order.pop(0) # BUG: O(n) 操作
            del self.cache[oldest]
        self.cache[key] = value
        self.order.append(key)

# 面试任务:
# 1. 找出所有性能 bug,说明每处的复杂度问题
# 2. 用 OrderedDict 或双向链表+哈希表重写,保证 get/put 均 O(1)
# 3. 补充边界测试:capacity=0、重复 put 同 key、get 不存在的 key
# 4. 不改变公开接口(方法名、参数、返回值),只改内部实现

这道题考验的是读代码、定位问题、在约束内重构的能力。AI 可以生成一个正确的 LRU 实现,但让它分析既有代码的 bug 并在不动接口的前提下修复——准确率显著下降。原因很简单:它缺少"这段代码为什么写成这样"的上下文理解。

转型清单

如果你的团队还在用 LeetCode 风格面试,以下是务实的过渡步骤:

步骤 行动 注意事项
1 承认现状 算法题已无法区分人类能力和 AI 输出,继续使用只会增加误判
2 保留基础编码验证 10 分钟的简单题仍有价值——确认候选人能写代码、能跑起来,但不作为主要筛选信号
3 引入改代码题 用真实 repo 的 bug 片段,观察定位和修复过程
4 加系统设计约束 给具体数字(QPS、延迟预算、存储限制),要求在约束内做决策
5 观察协作过程 结对编程或白板讨论,评估沟通和拆解能力
6 降低单题权重 用 3-4 个不同类型的短环节替代一道 45 分钟算法题

LeetCode 面试的死不是坏事。它逼我们回答一个被回避了十年的问题:我们到底想从面试中知道什么? 如果答案是"能不能干活",那就该用更接近真实工作的方式去验证。反转二叉树从来不是日常工作的核心——现在连验证它的价值都没有了。


相关推荐