openleetcode本地跑LeetCode:测试用例全开源你敢信!


openleetcode 是一个在本地运行 LeetCode 测试的工具,用 Haskell 编写。它的核心设计理念是将测试用例、运行时模板和 CLI 全部开源,让 LeetCode 的判题环境不再是黑盒。

项目标语:"we have democratized the LeetCode tests"(我们让 LeetCode 测试民主化了)

工作原理

  1. 接收一个普通的解决方案文件(如 solution.py)
  2. 根据题目 ID 或标题找到对应的测试清单(manifest)
  3. 构建一个轻量级的语言专属运行模板
  4. 交给可插拔的执行后端(目前使用 Piston)执行
  5. 在本地判断结果

支持的语言

支持 C++、Rust、Python3、Python2、Ruby、Java、C#、Kotlin、Go、Dart、Swift、TypeScript 共 12 种语言。
每种运行时都提供了 LeetCode 题目所需的兼容层:JSON 输出、数组、矩阵、链表、二叉树等。导入和公共库尽量与官方 LeetCode 环境保持一致,所以你的解法代码看起来和正常提交一样,不需要为 openleetcode 做特殊改写。

介绍

刷过 LeetCode 的人,都在做一件自欺欺人的事!

你写下的每一行代码,其实都运行在一个你永远看不见的黑盒子里!

LeetCode 的判题系统,对全球几百万程序员来说,就是一个巨大的谜。你提交代码,它告诉你“通过”或“不通过”,但你永远不知道背后发生了什么。测试用例长什么样,不知道;判题逻辑怎么跑的,不知道;甚至连它凭什么说你错了,你也只能猜。这个黑盒子统治了无数人的面试命运,却没人能打开它看一眼。直到一个叫 openleetcode 的项目出现,用 Haskell 写了一行命令,把这个黑盒子拆了个底朝天!


一个叫 openleetcode 的开源项目,正在把 LeetCode 从云端拽回你的电脑硬盘上。它做的事情很简单:让你在本地跑 LeetCode 的测试用例,不需要打开浏览器,不需要联网,不需要把代码交给任何远程服务器。你写一个 solution.py,敲一行 openleetcode submit ./solution.py --id 1,它就在你机器上把测试跑完,告诉你结果。但这句话背后藏着一个让整个 LeetCode 生态都尴尬的事实——原来那些你以为是“官方权威”的测试用例,不过是一些躺在 GitHub 仓库里的 YAML 文件。


你以为在跟 LeetCode 较劲,其实只是在跟一个 YAML 文件较劲

打开 openleetcode 的仓库,你会发现一个叫 tests 的文件夹。里面按题目编号整整齐齐排着目录:1-500、501-1000,每个目录下是一个题目的名字。点进去,有一个 manifest.yaml。这个文件里写的是什么,就是这个题目的全部测试用例。输入是什么,输出应该是什么,全部明明白白列在 YAML 里。

这就怪了。你在 LeetCode 网站上提交代码的时候,觉得自己是在跟一个庞大的、严肃的、不可置疑的官方系统打交道。但实际上,那个系统背后做的事情,跟你本地跑一个 YAML 文件没有任何本质区别。测试用例不是从什么神秘的数据源实时生成的,它们就是一些提前写好的静态数据。LeetCode 没有藏什么秘密武器,它只是把这些数据藏在了你够不着的地方。

openleetcode 做的事情,就是把这块遮羞布扯掉了。它把测试用例、运行时模板、判题逻辑全部开源,让你亲眼看见“通过”和“不通过”之间到底发生了什么。这个项目的标语说得很直白:“we have democratized the LeetCode tests”。翻译成大白话就是:我们让 LeetCode 的测试不再是谁家后院的秘密,而是每个人都能翻看的公共资料。

但事情到这里还没完。如果测试用例只是一些 YAML 文件,那 LeetCode 的“权威感”到底从哪来的!


你写的代码没变,变的是它跑在哪里

openleetcode 最狠的一招是:它不改你的代码。你在 LeetCode 网站上怎么写,在本地就怎么写。不需要改函数签名,不需要加额外的打印语句,不需要适配任何本地框架。它直接拿你那个 solution.py,塞进一个语言专属的“小马甲”里,扔给执行后端去跑。

这个“小马甲”就是 openleetcode 为每种语言准备的运行时模板。C++ 有 C++ 的模板,Python 有 Python 的模板,Rust 有 Rust 的模板。模板里包含了 LeetCode 题目常见的那点东西:JSON 输出、数组解析、矩阵处理、链表操作、二叉树构造。这些模板尽量模仿官方 LeetCode 的运行环境,所以你的代码在本地跑的结果,和在网上提交的结果应该是一样的。

目前 openleetcode 支持 12 种语言:C++、Rust、Python3、Python2、Ruby、Java、C#、Kotlin、Go、Dart、Swift、TypeScript。题量方面,不同来源的数据略有出入,有的说 800 道,有的说 1400 道。不管哪个数字,都覆盖了 LeetCode 上绝大多数热门题目。

但这里有一个巨大的“但是”——这个项目目前还只是 MVP(最小可行性产品)。系统设计题不支持,SQL 题不支持,并发题也不支持。也就是说,它能跑的,只是那些最标准的“写个函数、输入输出”类型的算法题。LeetCode 上那些更复杂的题型,它暂时还啃不动。

那问题来了:一个只能跑算法题的本地工具,为什么值得你花时间去了解!


开源的不是代码,是“凭什么”

你仔细想想,LeetCode 的测试用例为什么是保密的。不是技术原因,是商业原因。如果所有测试用例都公开了,那 LeetCode 的核心价值还剩什么,它的付费会员还卖什么。但 openleetcode 才不管这些,它直接把测试用例摊在 GitHub 上,谁都能看,谁都能改,谁都能提交新的。

这个行为本身,就是对“封闭判题”这种模式的一次精准打击。它用行动回答了一个问题:你到底是在学算法,还是在猜一个黑盒子的脾气。如果你在 LeetCode 上刷题刷了三个月,每次提交失败都在猜“它到底藏了什么测试用例没告诉我”,那你其实不是在学算法,你是在做逆向工程。你在猜一个你永远看不到的输入,在揣摩一个你永远不知道规则的裁判。

openleetcode 把这个游戏规则改写了。现在你可以在本地跑完所有测试,看到每一个输入输出,知道每一处失败到底是因为什么。你不需要再猜了。你可以大大方方地调试,可以一步一步跟踪,可以在本地 IDE 里打断点。这才是真正的练习,而不是在盲猜。

但别高兴太早。这个“所有测试都开源”的美好图景,有一个致命的前提——


谁在维护这 1400 道题的测试用例

openleetcode 的测试用例是从哪来的。不是从 LeetCode 官方偷来的,也不是用什么黑科技爬下来的。是 contributors 手动写的。每一个 manifest.yaml 都是人工整理的,每一组输入输出都是人填进去的。

这就意味着,测试用例的质量完全取决于贡献者的水平和细心程度。有的题目可能测试覆盖很全,边界条件都考虑到了;有的题目可能就随便写了两三个用例,聊胜于无。项目文档里自己都承认:部分 manifest 的质量参差不齐。

更麻烦的是,LeetCode 官方会不定期更新测试用例。今天你本地跑过了,明天 LeetCode 网站上可能新增了一个边界用例,你的代码在那里就挂了。openleetcode 不会自动同步这些更新,因为根本就没有同步的来源。它只能靠社区手动发现、手动补充。

所以 openleetcode 给出的承诺是“你的代码在本地跑的结果和在网上一样”,但这个“一样”是有条件的——前提是本地的测试用例和网上的测试用例是一致的。而这两者之间,没有任何自动化的同步机制。

这就引出了一个更深的悖论:如果你用 openleetcode 本地跑通了所有用例,提交到 LeetCode 却挂了,那到底是谁的问题!


Haskell 写的 CLI,Docker 跑的后端,这套组合拳你接得住吗

openleetcode 的 CLI 是用 Haskell 写的。选择 Haskell 本身就很有意思——这不是一个“大众语言”,写 LeetCode 工具的人选了一门函数式语言来做这件事。安装方式上,Linux 和 macOS 用户可以用一行 curl 命令搞定,Windows 用户用 PowerShell 脚本。安装脚本会自动通过 Docker Compose 启动一个叫 Piston 的执行后端。

Piston 是什么。它是一个通用的代码执行引擎,可以在隔离环境里跑各种语言的代码。openleetcode 把 solution 文件打包成 Piston 能接受的格式,发给它执行,然后拿到执行结果。默认配置指向 localhost:2000。

也就是说,openleetcode 本身只是一个“指挥家”,真正干活的是 Piston。你需要 Docker 来跑 Piston。Windows 用户安装 CLI 之后还得自己手动起 Docker。这套技术栈对普通刷题选手来说,门槛不算低。你得懂 Docker,得能跑容器,还得接受一个 Haskell 写的 CLI 在你的系统里运行。

但换个角度看,这也正是 openleetcode 的野心所在——它不打算做一个“傻瓜式”的刷题工具。它要的是一个可插拔、可扩展、可被其他工具集成的执行框架。CLI 只是胶水,真正的心脏是那些开源的测试用例和运行时模板。


本地跑通不算赢,提交通过才算数,那本地跑的意义是什么

这个问题才是 openleetcode 真正要回答的。如果你最终还是要回到 LeetCode 网站上去提交,那在本地跑一遍的意义到底是什么。

答案藏在一个你可能没注意到的细节里:openleetcode 的安装脚本里有一行命令叫 openleetcode download all。这行命令会把所有题目的测试数据下载到你本地。也就是说,你可以离线刷题。在飞机上、在地铁里、在没有网络的地方,你都可以打开电脑,写代码,跑测试,看结果。这才是 openleetcode 最实在的价值——它把 LeetCode 从一个“在线服务”变成了一个“本地资料库”。

另一个价值是:你可以用自己最喜欢的 IDE 来刷题。不用再忍受网页编辑器那有限的自动补全和调试能力。你可以用 VS Code,用 IntelliJ,用 Vim,用任何你顺手的工具。写完了,切到终端,敲一行命令,结果就出来了。这种工作流,比打开浏览器、登录账号、找到题目、粘贴代码、提交、等结果,要顺畅太多。

但 openleetcode 还有一个更深层的意义,它触及了 LeetCode 这个商业模式最脆弱的一环——


如果 LeetCode 的测试是开源的,那 LeetCode 还剩下什么

这不是一个假设性问题。openleetcode 的存在本身就是一个实验:当测试用例、运行时环境、判题逻辑全部开源之后,一个“在线判题平台”的核心价值还剩多少。

LeetCode 的价值从来不是“跑测试”这个动作。跑测试本身不值钱,随便一个脚本都能干。LeetCode 真正值钱的是三样东西:第一,它收集和整理了大量高质量的测试用例;第二,它提供了一个标准化的、公认的判题环境;第三,它的通过记录可以被用来证明你的能力。

openleetcode 直接干掉了第一样。测试用例开源了,谁都可以用。第二样也被削弱了——如果本地环境和官方环境足够接近,那本地跑通和官网提交之间的差距就缩小了。但第三样,openleetcode 动不了。你在本地跑通一百道题,没有人会承认你“通过了 LeetCode”。招聘方要看的是你 LeetCode 账号上的提交记录,不是你本地终端里的绿色输出。

所以 openleetcode 不是要取代 LeetCode,它是在给 LeetCode 做一面镜子。让每个刷题的人看清楚:你提交给 LeetCode 的代码,到底是在跟什么打交道。是跟一个神秘的、不可知的、高高在上的裁判打交道,还是跟一堆你可以亲手翻看的 YAML 文件打交道。

这面镜子照出来的东西,可能会让一些人不太舒服。


一个 YAML 文件能告诉你的事,比一个绿色对勾多得多

openleetcode 的贡献指南里有一句话:如果你不知道怎么贡献代码,就从 TEST_FORMAT.md 开始读。这个文件定义了 YAML、运行时模板和判题器之间的契约。换句话说,它告诉你一个测试用例到底应该长什么样。

读懂了这份契约,你就读懂了 LeetCode 的底层逻辑。你会发现,那些让你头疼的“隐藏测试用例”,本质上不过是一些提前写好的键值对。输入是一个数组,输出是一个整数;输入是一个字符串,输出是一个布尔值。没有魔法,没有黑科技,只有数据和规则。

这恰恰是 openleetcode 最反常识的地方——它用开源的方式,消解了 LeetCode 身上那层“权威”的光环。当你亲眼看见测试用例就是几个 YAML 文件的时候,你对“提交失败”这件事的恐惧感会大大降低。失败不再是一个神秘的判决,而是一个可以追溯、可以复现、可以修复的具体问题。

但 openleetcode 的项目文档里也坦诚地写着一句话:这个项目目前还处于早期阶段,部分 manifest 质量参差不齐。这意味着,如果你完全依赖 openleetcode 的测试用例来准备面试,你可能会漏掉一些官方新增的边界条件。你本地跑的是“社区版”的测试,而面试官看的是“官方版”的测试。这两者之间的差距,可能就是一道题从“通过”变成“不通过”的距离。


开源测试用例这件事,比你想象的要复杂得多

LeetCode 的测试用例为什么不能直接开源,除了商业原因之外,还有一个技术原因:测试用例本身是有“著作权”的。每一组输入输出,都是人工设计出来的,凝结了出题人对这道题的理解和对边界条件的判断。这些用例不是“事实”,而是“创作”。

openleetcode 的 contributors 在写 manifest.yaml 的时候,实际上在做一件很微妙的事情:他们在“复现”LeetCode 的测试用例,而不是“复制”。他们凭自己的理解,写出他们认为应该覆盖的输入输出。至于这些用例和官方用例有多少重合,没人知道,也没法验证。

这就引出了一个伦理问题:如果你用 openleetcode 本地跑通了所有用例,然后提交到 LeetCode 也通过了,那你的“通过”到底属于谁。是属于你掌握了算法,还是属于 openleetcode 的 contributors 帮你覆盖了所有边界。

这个问题没有标准答案。但有一点是确定的:openleetcode 让“刷题”这件事从“猜谜游戏”变成了“工程实践”。你不再是猜一个黑盒子的脾气,而是在本地搭建一个可调试、可追溯、可重复的开发环境。这个转变,比多刷一百道题更有价值。


一个跑在你自己电脑上的判题器,和 LeetCode 官方的判题器,差在哪里

答案是:差在“权威性”上。

LeetCode 官方的判题器,不管它写得多烂、多慢、多不透明,它给出的结果是被行业认可的。你在 LeetCode 上 AC 了一道题,你可以写在简历上。你在 openleetcode 上 AC 了一道题,你只能写“我在本地跑通了”。

但 openleetcode 的项目作者显然想得很清楚——他要的不是替代 LeetCode 的权威,他要的是打破 LeetCode 的神秘。他要让每一个刷题的人都知道:那个你敬畏的、恐惧的、觉得自己永远猜不透的判题系统,本质上不过是一个跑测试用例的程序。它不比你聪明,也不比你写的代码高贵。它只是一个工具,一个可以被理解、被拆解、被复现的工具。

这种“去神秘化”的努力,在编程教育领域其实非常稀缺。大多数在线判题平台都在刻意维持一种“黑盒”状态——你提交,我判题,你只知道结果,不知道过程。这种设计对平台有利,因为神秘感会催生敬畏,敬畏会催生付费。但对学习者不利,因为学习需要的是透明,是反馈,是可追溯的因果链。

openleetcode 选择站在学习者这一边。它把所有的卡片都翻到了桌面上。你看得见测试用例,看得见运行时模板,看得见判题逻辑。你甚至可以自己改,自己提交 PR,让这个工具变得更好。这种“参与式”的学习体验,是任何封闭平台都无法提供的。


这个项目最大的矛盾,藏在它的安装说明里

openleetcode 的 README 第一句就写着:“You need Docker for the execution backend”。一个用来“简化 LeetCode 刷题”的工具,首先要求你安装 Docker,还要能跑容器。这个门槛,把一大半潜在用户挡在了门外。

但换个角度想,这也恰恰说明了 openleetcode 的设计哲学——它不打算讨好所有人。它要服务的是那些已经有一定技术基础、不满足于在网页编辑器里写代码、愿意折腾本地环境的开发者。对于这些人来说,Docker 不是障碍,是日常。Haskell 写的 CLI 不是怪异,是新鲜。开源测试用例不是噱头,是刚需。

这个项目目前覆盖了大约 800 到 1400 道题,支持 12 种编程语言,但还不支持系统设计、SQL 和并发题。它的测试用例完全由社区维护,质量参差不齐。它的执行后端依赖 Piston,而 Piston 本身又是一个需要单独维护的服务。所有这些“不完美”加在一起,构成了 openleetcode 目前的状态——一个充满野心但尚在早期的开源项目。

但这个项目最有趣的地方不在于它现在能做到什么,而在于它指出了 LeetCode 这个庞然大物身上一个一直没人戳破的漏洞:你的测试用例,为什么不让我看!


openleetcode 把 LeetCode 的测试用例从云端拽到了本地硬盘上。它用 Haskell 写了一个 CLI,用 Docker 跑了一个 Piston 后端,用 YAML 存了上千道题的输入输出。它让你可以在飞机上刷题,可以用自己最喜欢的 IDE 调试,可以亲眼看见每一个测试用例长什么样。但它也留下了一个悬而未决的问题:如果社区的测试用例和官方的测试用例出现了分歧,你信谁。

这个问题没有答案,因为 openleetcode 和 LeetCode 之间的关系,从来就不是“替代”,而是“对照”。你用 openleetcode 本地跑,再用 LeetCode 官网提交,两次结果一致,说明你对了;两次结果不一致,说明有一个人错了。至于是谁错了,你得自己去查。而这个“自己去查”的过程,恰恰是 openleetcode 最想给你的东西——不是答案,是查答案的能力。

原文期刊:GitHub / 发布日期:2026-01-13 / 原文标题:openleetcode - we have democratized the LeetCode tests / 作者单位背景:therepanic(个人开发者)