news 2026/9/10 2:22:09

freeCodeCamp 每日编程挑战实战解析:用 Python 解决 Missing Numbers(Challenge 34)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
freeCodeCamp 每日编程挑战实战解析:用 Python 解决 Missing Numbers(Challenge 34)

freeCodeCamp 每日编程挑战实战解析:用 Python 解决 Missing Numbers(Challenge 34)

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

本篇技术指南围绕 freeCodeCamp 开源仓库中每日编程挑战(Daily Coding Challenge)系列的第 34 题 Missing Numbers 展开,完整还原题目约束、测试用例与官方参考实现,并结合仓库源码剖析这道 Python 题目从课程文件、种子数据到 API 服务的完整落地链路。读完本文,你将掌握这道缺失数字问题的分析思路与 Python 实现,并理解这类题目在 freeCodeCamp 项目中是如何被定义、校验、存储与分发的。

挑战全景:Missing Numbers 在项目中的位置

该题目位于 Python 每日挑战块(block)daily-coding-challenges-python中,源文件为 curriculum/challenges/english/blocks/daily-coding-challenges-python/68af0687ef34c76c28ffa54f.md。题目 id 为68af0687ef34c76c28ffa54f,标题为 "Challenge 34: Missing Numbers",challengeType: 29(对应 Python 侧练习),dashedNamechallenge-34

从块配置文件 curriculum/structure/blocks/daily-coding-challenges-python.json 可以看到该块的元信息:

  • isUpcomingChange: true:标记为新体系中的变更内容;
  • usesMultifileEditor: true:练习在多功能编辑器中完成;
  • helpCategory: "Python":帮助分类为 Python;
  • blockLayout: "legacy-challenge-list":采用旧式挑战列表布局;
  • challengeOrder:包含 200+ 道按日编号的挑战,Challenge 34 只是其中一环,前后分别是 "Challenge 33: Screen Time" 与 "Challenge 35: Word Frequency"。

值得注意的一点是:同一道题存在 JavaScript 与 Python 两个独立版本。Python 版要求实现find_missing_numbers(arr),而 JS 版对应文件 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68af0687ef34c76c28ffa54f.md(challengeType: 28)要求实现findMissingNumbers(arr)。两个版本题目描述与 6 组测试用例完全一致,只是语言 API 不同——这为后面介绍的“双语言配对入库”机制埋下伏笔。

题目要求详解

原题描述非常精炼,核心是一句话:

给定一个包含从1n(含端点)整数的数组,返回所有介于1n之间缺失的整数,其中n是给定数组中的最大值。

同时附带三条约束:

  1. 输入数组可能未排序,且可能包含重复元素——意味着不能依赖数组顺序,也不能假定元素唯一;
  2. 返回数组必须按升序排列——例如[2, 4]而不是[4, 2]
  3. 如果没有缺失整数,返回空数组——即数组恰好完整覆盖了1..n

题目没有显式声明空输入的处理,但官方参考实现对空数组做了兜底(返回[]),这也是判题时应当考虑到的健壮性边界。

边界语义澄清

  • n由输入数组的最大值决定,而不是由数组长度决定。例如[10, 1, 10, 1, 10, 1]n = 10,因此要检查的完整区间是1..10,而不是1..6
  • 重复元素不影响结果:查找区间内某个整数“是否缺失”只看它是否至少出现一次,出现多次与出现一次等价。
  • 数组未排序:实现时不能使用“相邻元素差 1”这类依赖顺序的快捷方式,需要先建立全局视角(如集合)。

测试用例逐条解析

原文档通过 6 组hints定义了完整的行为契约。Python 版采用runPython机制,在测试环境内执行unittest.TestCase().assertEqual(...)来断言结果,覆盖了典型场景、边界场景与极端场景:

输入期望输出覆盖点
[1, 3, 5][2, 4]基本缺失场景,中间连续缺两个数
[1, 2, 3, 4, 5][]无缺失,完整区间
[1, 10][2, 3, 4, 5, 6, 7, 8, 9]大区间、端点仅有首尾
[10, 1, 10, 1, 10, 1][2, 3, 4, 5, 6, 7, 8, 9]未排序 + 重复元素,且n为最大值 10
[3, 1, 4, 1, 5, 9][2, 6, 7, 8]未排序 + 重复,缺失分散在中间与尾部
[1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 6, 8, 9, 3, 2, 10, 7, 4][11]长数组 + 大量重复,仅缺一个数

这 6 组用例合计覆盖了:升序输出、空结果、重复元素、未排序、n取最大值、单点缺失等全部语义。测试文件中的断言写法可直接用于本地验证,例如:

from unittest import TestCase TestCase().assertEqual(find_missing_numbers([1, 3, 5]), [2, 4]) TestCase().assertEqual(find_missing_numbers([1, 2, 3, 4, 5]), [])

参考实现逐步拆解

题目的种子代码(--seed-contents--)给出如下函数骨架,要求补全逻辑:

def find_missing_numbers(arr): return arr

官方参考解法则给出了完整实现:

def find_missing_numbers(arr): if not arr: return [] n = max(arr) seen = set(arr) result = [i for i in range(1, n + 1) if i not in seen] return result

逐行分析:

  1. 空数组兜底if not arr: return []。虽然题目未显式说明,但官方解法对空输入返回空列表,避免后续max(arr)ValueError
  2. 确定上界n = max(arr)max遍历一次数组找到最大值,这就是区间1..n的上界,直接对应题目中“n是给定数组最大值”的定义。
  3. 去重建集seen = set(arr)。把整个数组转成集合,一次性消化“未排序 + 重复元素”两条约束,使后续查询降为 O(1)。
  4. 遍历区间筛缺失result = [i for i in range(1, n + 1) if i not in seen]。从 1 递增到n生成完整区间,只保留不在集合中的数。由于range天然升序,输出的result自动满足“升序排列”要求,无需额外排序。
  5. 返回结果:无缺失时列表推导自然得到空列表[],与第三条约束吻合。

复杂度分析

  • 时间复杂度 O(n)max一次 O(n),建set一次 O(n),列表推导遍历1..n共 O(n)(最坏情况下n与输入规模同量级)。整体线性。
  • 空间复杂度 O(n)seen集合至多容纳n个不同元素,result最坏也接近n个元素。

作为对比,若不使用集合而用if i not in arr逐次线性查找,时间复杂度会退化为 O(n²);若先把数组去重排序再逐个比对,代码会明显更长且同样需要额外空间。官方实现是“语义清晰 + 线性效率”的平衡解。

可选变体

  • 布尔标记数组:若n有限且可接受 O(n) 空间,可用[False] * (n + 1)标记出现过的数字,再收集未标记下标;
  • 原地哈希 / 符号标记:利用下标与值域的对应关系在输入数组上打标记,可把空间降到 O(1),但会修改输入,且 Python 实现可读性不如集合方案。

仓库源码佐证:从课程 Markdown 到线上服务的完整链路

这道题并非孤立文本,它在 freeCodeCamp 仓库中形成了一条可追溯的数据链路,理解它有助于把“做题”与“平台实现”连成整体。

双语言配对与种子数据

从 tools/daily-challenges/seed-daily-challenges.ts 的注释与 tools/daily-challenges/helpers.ts 的fetchChallenges实现可以看到,种子脚本通过 GraphQL 从dev-playgroundsuperblock 中按daily-coding-challenges-javascript/daily-coding-challenges-python两个块分别拉取挑战,再调用combineChallenges同一挑战号的 JS 与 Python 版本配对合并:标题、描述、测试数量必须一致,否则抛出异常(helpers.ts中显式校验jsTitle !== pyTitlejsDescription !== pyDescriptionjsTests.length !== pyTests.length)。合并后的文档包含challengeNumbertitledatedescription以及javascript/python两个语言的testschallengeFiles,写入 MongoDB 的dailyCodingChallenges集合。

API 分发

api/src/daily-coding-challenge/routes/daily-coding-challenge.ts 提供了若干公开 GET 路由,用于按日期/天/月/全部/最新查询挑战:

  • /daily-coding-challenge/today:返回当天(美国中部时区)挑战;
  • /daily-coding-challenge/date/:date:按YYYY-MM-DD查询,非法格式返回 400,未来或不存在返回 404;
  • /daily-coding-challenge/day/:day:按MM-DD查询;
  • /daily-coding-challenge/month/:month:按YYYY-MM返回当月列表(仅含 id、challengeNumber、date、title);
  • /daily-coding-challenge/all/daily-coding-challenge/newest:分别返回全部已发布挑战与最新挑战日期。

该模块的说明见 api/src/daily-coding-challenge/README.md,其中明确“每日挑战的提交仍走主 API 的 challenge 提交路由”,即这些端点只负责取题信息。

客户端校验与渲染

client/src/utils/daily-coding-challenge-validator.ts 用 Joi 定义了DailyCodingChallengeFromDb的校验结构:idchallengeNumber(整数且 ≥1)、titledatedescription,以及javascriptpython两个语言对象,各自包含teststext+testString)与challengeFilesfileKey+contents)。Challenge 34 的 Python 版teststestString正是我们在文中看到的runPython断言代码,challengeFiles则对应种子里的find_missing_numbers骨架。

由此可以确认:本文所讲题目的描述、测试与初始代码,最终会经由种子脚本进入数据库,再通过上述 API 下发到客户端渲染并判题——一条从curriculum/challenges/english/blocks/daily-coding-challenges-python/68af0687ef34c76c28ffa54f.md出发、贯穿tools/daily-challenges/api/src/daily-coding-challenge/的完整链路。

本地验证与运行建议

若想在本地验证这道题的实现,可以按以下方式操作(仓库只读,仅介绍查看与运行方式):

  1. 静态对照:阅读 Python 版题目 与 JS 版题目 的--solutions--段,对比两种语言实现思路;
  2. 本地执行测试:将 6 组hints中的断言整理为 Python 脚本,直接运行python3验证你的find_missing_numbers实现;
  3. 体验完整链路:若要实际看到题目的线上形态,可参照 tools/daily-challenges/seed-daily-challenges.ts 运行种子脚本(需先启动 client 的 GraphQL 端点与 MongoDB),再启动 API 后通过/daily-coding-challenge/today等端点观察下发数据;注意种子脚本假定客户端运行在http://localhost:8000/___graphql,且按日期调度,Challenge 34 只在对应日期才会作为“今日挑战”出现。

小结

Missing Numbers 是一道“描述极简、边界清晰”的数组题:以最大值为区间上界,用集合消化未排序与重复两条约束,再用升序遍历收集缺失项,即可同时满足输出的升序要求与空结果约定。官方参考实现以 O(n) 时间、O(n) 空间的集合方案给出简洁答案,而仓库中与其配套的双语言挑战文件、种子配对脚本、API 分发路由与客户端校验器,共同构成了 freeCodeCamp 每日编程挑战从题目定义到线上交付的完整工程化闭环。掌握这道题,既是一次 Python 数组/集合基本功的巩固,也是一次理解开源平台“课程内容如何变成线上练习”的绝佳入口。

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 2:21:07

视觉SLAM数据采集实战:从时间戳到OIS防抖的坑与解法

简介:面向同步定位与建图(SLAM)及运动恢复结构(SfM)研究者的安卓数据采集工具,可一体化捕获视频、惯性测量单元数据和相机参数,帮助解决三维重建中的数据来源问题。该应用以约三十赫兹录制H.264…

作者头像 李华
网站建设 2026/9/10 2:20:42

零成本AI短剧制作:本地部署Ollama+ComfyUI+FFmpeg实战

“一个社恐程序员深夜加班时捡到一只会说话的猫,猫用三句话说服他辞职创业。”——拿这句台词去做一条AI短剧,照一年前的主流玩法得先充会员、再买图生视频额度、配音还要单独订套餐,一套组合拳下来,一条30秒的片子可能就要花掉几…

作者头像 李华
网站建设 2026/9/10 2:18:31

免费云服务器深度实测:从注册到部署的完整指南与避坑要点

开头先劝退一下:如果你以为“免费云服务器”就是注册个账号,然后永久免费拿一台配置不错、永远在线的机器,那建议直接关掉这篇。真实的免费云服务器,本质是云厂商放出来的“试用装”或者“永久低配款”,目的不是做慈善…

作者头像 李华
网站建设 2026/9/10 2:18:15

ComputeShader全面解析:从线程组原理到GPU并行计算实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华