尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

freeCodeCamp 每日编程挑战实战:Challenge 117 “Symmetric Difference“(对称差集)完整解法剖析

freeCodeCamp 每日编程挑战实战:Challenge 117 “Symmetric Difference“(对称差集)完整解法剖析 freeCodeCamp 每日编程挑战实战Challenge 117 Symmetric Difference对称差集完整解法剖析【免费下载链接】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 ChallengesJavaScript题库的第 117 道题目展开围绕“对称差集Symmetric Difference”的定义、顺序约束、去重陷阱与官方参考实现进行源码级拆解。读完你将掌握这道题的标准解法、边界条件的推导方法并理解这类 Markdown 题目在 freeCodeCamp 仓库中从题库、测试断言到线上每日挑战的完整流转链路从而能够举一反三地解决题库中其余 300 多道同类题目。挑战档案题目在仓库中的位置与元信息本题目对应的源文件为 69162d64f96574d9bb629f02.md其 frontmatter 如下--- id: 69162d64f96574d9bb629f02 title: Challenge 117: Symmetric Difference challengeType: 28 dashedName: challenge-117 ---几个值得注意的元数据点从 daily-coding-challenges-javascript.json 的challengeOrder数组可以看出该文件在块内按标题序列号排在第 117 位前一题是 Challenge 116: Permutation Count后一题是 Challenge 118: Date Formatter因此题目以challenge-117作为dashedName这也是挑战文件的命名约定。邻近题目如 Challenge 118 Date Formatter同样声明challengeType: 28且使用完全相同的文档结构说明这是该题库统一的“编码挑战”题型模板。该块同时是 dev-playground.json 中daily-coding-challenges-javascript与daily-coding-challenges-python两个并行的每日挑战块之一且块配置中标有isUpcomingChange: true属于仍在迭代开发期的实验性课程内容。题目理解到底要算什么原文档给出的任务定义是Given two arrays, return a new array containing the symmetric difference of them.The symmetric difference between two sets is the set of values that appear in either set, but not both.Return the values in the order they first appear in the input arrays.把集合论的对称差概念翻译成可执行的规则共有三层要求取并集中“恰好属于其中一个集合”的元素。对称差集的符号记法为 A △ B (A \ B) ∪ (B \ A)也就是“出现在任一数组中、但不同时出现在两个数组中的值”。出现在两个数组中的交集部分必须被剔除。结果去重。由于把数组当作“集合”看待输入数组中某个值的多次重复出现最终输出里只能保留一次。换言之输出是一个“值集合”而不是重复值的列表。保持出现顺序。输出数组按该值在两个输入数组中首次出现的先后次序排列先扫描arr1中符合条件的值再追加arr2中符合条件的值。因为被剔除的都是交集值剩下的每个值都只属于一边这种“先扫arr1、再扫arr2”的顺序天然与全局首次出现顺序一致。一个需要留意的隐含细节是数组比较使用严格相等语义下文会看到官方实现用Array.prototype.includes其内部基于SameValueZero比较1与1会被视为不同值因此不同类型元素会按原样保留。官方测试用例逐条解读原文档的# --hints--区块给出了四个断言全部使用assert.deepEqual进行深度相等比较即逐元素比较内容与顺序而非引用比较调用期望输出设计意图difference([1, 2, 3], [3, 4, 5])[1, 2, 4, 5]最基本场景仅有一个公共值3difference([a, b], [c, b])[a, c]字符串数组公共值为bdifference([1, a, 2], [2, b, a])[1, b]混合数字与字符串公共值为2与a验证严格相等语义与类型保留difference([1, 3, 5, 7, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9])[2, 4, 6, 8]大数据量场景奇数全部在交集中被剔除剩偶数其中第三个用例对“严格相等 类型保留”的验证尤为关键arr1中的1是数字、a是字符串arr2中的2、b、a。公共元素为2数字与a字符串两者剔除后剩余1与b且各自保持原类型。如果你错误地使用宽松转换比较或先字符串化再比较就会在此用例上失败。第四个用例则验证顺序与批量剔除逻辑arr1 [1,3,5,7,9]全部奇数在arr2中都存在因此arr1无贡献arr2中剔掉全部奇数后按剩余顺序输出偶数[2,4,6,8]。题目给出的初始代码seed# --seed--区块为学习者提供函数骨架function difference(arr1, arr2) { return arr1; }函数名固定为difference接收两个数组参数arr1、arr2要求返回一个新数组。注意骨架里的return arr1只是占位逻辑直接提交仅能通过“两数组无交集且第一个数组较短”这类侥幸场景——例如它对前四个用例全部失败因为它既不剔除交集值、也不追加第二个数组的独有值、还直接返回原数组引用。官方参考实现逐行拆解# --solutions--区块给出的参考解如下function difference(arr1, arr2) { const diff []; for (const v of arr1) { if (!diff.includes(v) !arr2.includes(v)) diff.push(v) } for (const v of arr2) { if (!diff.includes(v) !arr1.includes(v)) diff.push(v) } return diff; }它采用“两次线性扫描 双保险判重”策略整体思路非常直白第一阶段处理arr1。用for...of遍历arr1的每个元素v只有同时满足两个条件才推入结果!diff.includes(v)该值尚未出现在结果中。由于我们按arr1的原始顺序遍历这确保同一值的重复出现不会重复入列同时也保证了输出结果的有序性与唯一性!arr2.includes(v)该值不在另一个数组中即不是交集元素。第二阶段处理arr2。用同样的模式遍历arr2条件为!diff.includes(v) !arr1.includes(v)。这里的!arr1.includes(v)把交集元素挡在门外而!diff.includes(v)承担两重职责一方面清理arr2内部的重复值另一方面兜底防止与第一阶段已加入的元素重复虽然对一个“同时属于两边”的值而言它必然已被第二条件拦截但保留此判断让逻辑更稳健、语义更明确。返回值。直接返回累积的新数组diff不修改输入数组符合“return a new array”的题目约束。我们用第二个用例快速走一遍执行轨迹difference([a, b], [c, b])。diff []。扫arr1a不在diff、不在arr2→ 推入diff [a]b不在diff但arr2.includes(b)为true→ 跳过。扫arr2c不在diff、不在arr1→ 推入diff [a, c]b在arr1中 → 跳过。返回[a, c]与断言一致。复杂度评估。由于includes()需要对数组做线性扫描外层又是线性遍历该实现的最坏时间复杂度是 O(n·(n m) m·(n m))n、m 分别为两数组长度即平方级空间上额外维护一个diff数组。对每日挑战这种以“值范围小、输入规模可控”为设计前提的入门到中级题目而言完全够用。从题库到线上挑战题在 freeCodeCamp 工程中的流转这道 Markdown 题目并不是孤立的练习题它背后是 freeCodeCamp 一整套“每日编程挑战”生产链路仓库内可以交叉验证到多个环节的实现题库侧本文件即其一题目文档的 frontmatter 中title、dashedName、challengeType由 daily-coding-challenges-javascript.json 的challengeOrder登记成序两个语言块被归入 dev-playground.json 这个“开发试验场”超块。取数与判题脚本seed-daily-challenges.ts 通过 GraphQL 从 dev-playground 超块抓取挑战数据并强制校验 JavaScript 与 Python 两个块的数量一致EXPECTED_CHALLENGE_COUNT 365随后以bulkWrite replaceOne upsert的方式写入 MongoDB 的DailyCodingChallenges集合。其配对逻辑在 helpers.ts 中实现fetchChallenges(language)查询每个挑战的description、tests与challengeFilescombineChallenges再校验两种语言的描述与测试数量一致最后把测试用例与初始代码拼装进对应语言子对象——也就是说本文件# --hints--里的assert.deepEqual断言会被收集为tests含text与testString# --seed--的内容则进入challengeFiles。运行与部署说明tools/daily-challenges/README.md 记载了完整跑法把sample.env复制为.env、安装依赖、以“显示 upcoming changes”的方式运行主客户端使 GraphQL 可访问进入tools/daily-challenges后执行pnpm seed-daily-challenges即可把挑战写入本地或生产库。客户端校验侧daily-coding-challenge-validator.ts 中的 Joi schema 印证了上述数据结构——它要求每日挑战对象必须同时包含javascript与python两个语言子对象每个子对象都要有teststexttestString和challengeFilesfileKeycontentschallengeNumber须为正整数。这解释了为什么题库要求 JS 与 Python 双份题面一份挑战在两个语言下保持平行。由此可见学习者在本挑战中填写的函数最终会成为数据库DailyCodingChallenges集合中某条记录tests.testString的评判目标并与日期首个挑战从 2025-08-11 UTC 起每日递增绑定后呈现给用户。扩展思考更优与更简洁的替代实现在动手前先明确官方解法的“护栏”逻辑其实等价于三个集合操作A独有值 B独有值 全局去重。基于这一洞察可以用Set把两个“判断集合”与一个“去重集合”显式分离将时间复杂度降到线性function difference(arr1, arr2) { const in1 new Set(arr1); const in2 new Set(arr2); const result []; const seen new Set(); for (const v of [...arr1, ...arr2]) { // 恰好只属于一个集合in1.has(v) ! in2.has(v) if (in1.has(v) ! in2.has(v) !seen.has(v)) { seen.add(v); result.push(v); } } return result; }这里用in1.has(v) ! in2.has(v)来判定“属于其一而不属于其二”本质是对集合论中“异或”关系的直接编码比“两次排除交集 判重”更贴近数学定义也天然满足“按首次出现顺序”的输出要求因为仍是对arr1、arr2的拼接顺序做单遍扫描。如果偏好函数式风格也可以基于filter写一个可读版本但务必注意去重边界——如果不做额外处理输入数组内部的重复值会被filter原样输出多份从而破坏“集合”语义function difference(arr1, arr2) { const in1 new Set(arr1); const in2 new Set(arr2); const once new Set(); return [...arr1, ...arr2].filter(v { const keep in1.has(v) ! in2.has(v) !once.has(v); if (keep) once.add(v); return keep; }); }对题目规模的输入而言官方参考解与上述 Set 版在结果上完全等价若要追求面试或实际工程中的稳健性例如超长数组、需多次调用优先选择 Set 线性版本。练习时建议先独立推演“先扫arr1、再扫arr2、双条件判重”的过程再用四个官方断言逐一验证随后对比includes与Set.has两种判重手段的复杂度差异这道 Challenge 117 就真正吃透了。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表