
freeCodeCamp Python 每日编程挑战第 31 关 Array Diff对称差集与字母排序完整解析【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本篇技术指南围绕 freeCodeCamp 课程仓库中daily-coding-challenges-python区块的第 31 个挑战Array Diff展开完整拆解题目语义、5 个官方测试用例的判定逻辑、种子代码的改造路径与参考解法并结合 挑战源文件、API 路由实现 与 种子脚本 说明这类挑战从 Markdown 文档到数据库记录、再到每日投递与自动判题的全链路机制。读完本文你将掌握对称差集symmetric difference的多种 Python 实现、去重与排序的边界处理以及 freeCodeCamp 每日编程挑战体系的源码级工作原理。挑战定位每日编程挑战系列中的一环在 freeCodeCamp 课程仓库中每日编程挑战Daily Coding Challenge由 JavaScript 与 Python 两套平行区块组成分别位于daily-coding-challenges-javascript与daily-coding-challenges-python。区块结构文件 记录了该区块的元信息isUpcomingChange: true——该区块作为即将上线的新内容维护需要通过环境变量开启展示usesMultifileEditor: true——挑战使用多文件编辑器环境helpCategory: Python——归类到 Python 帮助分类blockLayout: legacy-challenge-list——采用传统挑战列表布局。Array Diff 是该区块的第 31 个挑战其挑战文档的 frontmatter 标注为id: 68af0687ef34c76c28ffa549——全局唯一挑战 ID也是挑战完成记录与数据库中记录关联的主键title: Challenge 31: Array DiffchallengeType: 29——对应多文件编辑器的挑战类型dashedName: challenge-31。在 区块结构文件 的challengeOrder中它紧随 Challenge 30: Unique Characters后接 Challenge 32: Reverse Sentence是整套每日挑战难度递进序列中的一环。题目语义拆解只出现在一个数组中的值挑战的--description--部分给出了核心需求Given two arrays with strings values, return a new array containing all the values that appear in only one of the arrays. The returned array should be sorted in alphabetical order.翻译为两层约束集合语义给定两个仅含字符串的数组返回只出现在其中一个数组的所有值。这正是数学上的对称差集symmetric difference记作 A △ B(A − B) ∪ (B − A)即属于 A 但不属于 B、以及属于 B 但不属于 A 的元素。输出排序返回数组必须按字母顺序alphabetical order排序。需要注意题目的措辞 appear in only one of the arrays——它关注的是值是否存在因此重复元素也是隐含考察点参考解法首先对两个输入数组分别去重再去求对称差。这从 挑战源文件 的--solutions--段可以清楚看到def array_diff(arr1, arr2): unique1 [] for v in arr1: if v not in unique1: unique1.append(v) unique2 [] for v in arr2: if v not in unique2: unique2.append(v) only1 [v for v in unique1 if v not in unique2] only2 [v for v in unique2 if v not in unique1] return sorted(only1 only2)参考解法分为三步分别去重用v not in unique1的线性查找方式把arr1、arr2各自折叠成无重复序列unique1、unique2双向过滤only1保留unique1中不在unique2的值only2保留unique2中不在unique1的值二者合并即为对称差集排序返回sorted(...)对合并结果做字母序排序。去重这一步是解题的关键若不去重对于含重复值的输入输出中会残留重复项无法精确满足值只出现在一个数组中的集合语义。官方测试用例逐一验证挑战源文件 的--hints--段内置了 5 个由runPythonunittest.TestCase().assertEqual执行的测试它们共同界定了函数必须满足的行为输入 arr1输入 arr2期望输出覆盖要点[apple, banana][apple, banana, cherry][cherry]仅 arr2 多出的值应被返回[apple, banana, cherry][apple, banana][cherry]仅 arr1 多出的值应被返回方向对称[one, two, three, four, six][one, three, eight][eight, four, six, two]多元素差集 输出必须字母排序[two, four, five, eight][one, two, three, four, seven, eight][five, one, seven, three]输出与输入顺序完全无关只按字母序[I, like, freeCodeCamp][I, like, rocks][freeCodeCamp, rocks]区分大小写大写I与小写单词不混淆第 3、4 个用例重点校验排序例如第三个用例中两数组的公共元素是one与three差集元素为two、four、six、eight期望输出按字母序为[eight, four, six, two]与输入数组中的出现顺序完全不同。第 5 个用例验证字符串比较是区分大小写的I不会被当作与like之类的小写词相同。在课程测试体系中这些 hint 会被解析为text展示给学习者的说明文本与testString实际执行的判定代码对应 Prisma 模型中DailyCodingChallengeApiLanguageTests的两个字段详见下文从 Markdown 到数据库一节。从种子代码出发最小改造思路挑战的--seed--段给出了初始代码学习者需要在此骨架之上完成实现def array_diff(arr1, arr2): return arr1种子代码目前直接返回arr1显然无法通过任何用例。一个保持官方解法思路、但对学习者更友好的写法是在原函数内完成去重—求差—排序三步def array_diff(arr1, arr2): unique1 list(dict.fromkeys(arr1)) # 保持顺序去重 unique2 list(dict.fromkeys(arr2)) only1 [v for v in unique1 if v not in unique2] only2 [v for v in unique2 if v not in unique1] return sorted(only1 only2)dict.fromkeys利用了字典键的唯一性同时保留元素首次出现的顺序由于最终结果要排序顺序保持并非必需但能让中间步骤更直观。官方参考解法使用的v not in unique1线性查找同样成立二者都能通过全部 5 个测试。进阶方案用集合运算实现对称差集既然题目本质是求对称差集Python 内置的set类型提供了两种直接表达方式def array_diff(arr1, arr2): s1, s2 set(arr1), set(arr2) return sorted(s1 ^ s2) # 对称差集运算符或使用集合方法def array_diff(arr1, arr2): return sorted(set(arr1).symmetric_difference(arr2))这两种写法更简洁且set的哈希查找让整体复杂度从参考解法的 O(n·m) 降到 O(n m)。需要注意一个行为差异set会同时完成去重与去顺序因此当输入含重复元素时集合方案天然满足值只出现一次的集合语义与官方参考解法的去重意图一致。复杂度对比方案去重方式差集计算时间复杂度空间复杂度官方参考解法线性查找in于列表双向列表过滤O(n·m)n、m 为两数组长度O(n m)dict.fromkeys 列表过滤字典键去重双向列表过滤O(n m) 去重 O(n·m) 过滤O(n m)set对称差集哈希集合^运算符O(n m)O(n m)对于字符串数组且规模不大的每日挑战场景三种方案均能通过全部测试官方解法刻意避开set可能是为了让学习者练习列表推导与去重逻辑这一点从源码可以确认——挑战源文件 的参考解法全程只使用列表与sorted。常见陷阱与边界情况结合题目约束与测试用例容易踩坑的点包括忘记排序只返回差集而不调用sorted()会直接导致第 3、4 个用例失败——期望输出严格按字母序。忘记去重若输入数组含重复值题目未禁止不去重会产生重复输出破坏集合语义。方向遗漏只计算arr1 - arr2而忽略arr2 - arr1会让第 1 个用例cherry只在 arr2返回空数组。大小写混淆字符串比较区分大小写I与i是不同值。原地修改输入sorted()返回新列表若误用list.sort()会修改原数组的引用虽然测试只断言返回值但保持函数无副作用是良好实践。源码级原理挑战如何从 Markdown 变成每日投递Array Diff 这类挑战并不是简单静态页面而是经由课程内容 → GraphQL → 种子脚本 → MongoDB → API → 客户端组件的完整流水线呈现在学习者面前。数据库模型Prisma Schema 定义了DailyCodingChallenges模型model DailyCodingChallenges { id String id default(auto()) map(_id) db.ObjectId challengeNumber Int date DateTime title String description String javascript DailyCodingChallengeApiLanguage python DailyCodingChallengeApiLanguage } type DailyCodingChallengeApiLanguage { tests DailyCodingChallengeApiLanguageTests[] challengeFiles DailyCodingChallengeApiLanguageChallengeFiles[] }每条记录同时携带 JavaScript 与 Python 两个语言版本testschallengeFilesdate字段决定挑战在哪一天对外可见——这正是每日机制的落点。种子脚本与语言一致性校验tools/daily-challenges/seed-daily-challenges.ts 负责把课程内容灌入数据库它从运行中的客户端 GraphQL 端点http://localhost:8000/___graphql按superBlock: dev-playground、block: daily-coding-challenges-python以及 JavaScript 版本拉取全部挑战逐条配对生成记录。脚本内置了严格的一致性断言期望挑战总数为 365EXPECTED_CHALLENGE_COUNTJS 与 Python 数量必须相等首条挑战的日期被固定为2025-08-11之后每天递增一天且脚本会在起始日期被意外改动时直接抛错防止生产环境已发布内容错位helpers.ts 的combineChallenges在合并时校验 JS/Python 两版的title、description、tests数量完全一致任一不匹配即拒绝写入记录_id直接取用 JS 挑战的 id如本文挑战的68af0687ef34c76c28ffa549保证挑战完成记录与课程内容可互相追踪。与之对应的课程级校验在 curriculum/src/test/daily-challenges.test.js通过getChallenges(CURRICULUM_LOCALE, { superBlock: dev-playground })加载挑战后逐一断言 JS/Python 两个区块的挑战数量、ID、标题、描述与测试数量匹配。API 投递与客户端入口挑战对外暴露的读取接口位于 api/src/daily-coding-challenge/routes/daily-coding-challenge.ts共 6 个 GET 端点端点参数格式行为/daily-coding-challenge/date/:dateYYYY-MM-DD按具体日期取挑战/daily-coding-challenge/day/:dayMM-DD按月-日取自动匹配到对应年份/daily-coding-challenge/today无返回美国中部时间当天的挑战/daily-coding-challenge/month/:monthYYYY-MM返回某月挑战摘要列表/daily-coding-challenge/all无返回全部已发布挑战摘要/daily-coding-challenge/newest无返回最新挑战日期值得注意的约束所有端点都只返回今天美国中部时间之前的挑战challenge.date getUtcMidnight(getNowUsCentral())会被 404 拦截保证未发布内容不可见。请求参数的模式校验由 api/src/daily-coding-challenge/schemas/daily-coding-challenge.ts 中的 TypeBox Schema 完成例如日期必须是YYYY-MM-DD格式、单条响应的id必须是 24 位 ObjectId。每条成功/失败记录还会通过 Sentry metrics 上报dcc.challenge_viewed、dcc.challenge_not_found、dcc.request_failed等指标。客户端侧widget.tsx 中的DailyCodingChallengeWidget组件在课程地图与首页渲染两个入口按钮进入今日挑战链接由getMonthDayUsCentral()生成MM-DD格式以及进入历史档案库。学习者在页面中编写array_diff并通过全部 5 个 hint 后提交完成记录走的是主挑战完成流程API README 明确说明Daily challenge submission still lives in the main part of the API。总结Array Diff 看似是一个简单的双数组求差题但它在 freeCodeCamp 的每日编程挑战体系中承载了完整的学习闭环理解对称差集的集合语义、掌握去重与字母排序的边界、对比set与列表推导两种实现风格。透过 挑战源文件 与 区块结构文件、Prisma 模型、API 路由、种子脚本 与 课程测试 的源码证据还能看到一道 Markdown 挑战如何被校验、入库、按日投递并被自动判题——这正是把刷题升级为理解平台机制的进阶视角。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考