ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

freeCodeCamp 每日编程挑战解析:用欧几里得算法求最小公倍数(LCM)

freeCodeCamp 每日编程挑战解析:用欧几里得算法求最小公倍数(LCM) freeCodeCamp 每日编程挑战解析用欧几里得算法求最小公倍数LCM【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本篇技术指南以 freeCodeCamp 开源课程仓库中的 Challenge 103: LCM 挑战文档curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68ffb91507a5b645769328c6.md为主体讲解如何在 JavaScript 中实现最小公倍数Least Common MultipleLCM算法并以仓库源码为佐证揭示这道题目从课程 Markdown 到线上做题环境的完整流转链路。读完本文你将掌握 LCM 的数学定义与测试判定方法、欧几里得辗转相除算法求最大公约数的递归实现并理解这类题目在 freeCodeCamp 平台中如何被校验、入库并被每日呈现给学习者。挑战背景它属于哪个体系Challenge 103: LCM 并非独立的一道随堂测验而是 freeCodeCamp 课程仓库中**每日编程挑战Daily Coding Challenge**序列的第 103 题。从课程结构文件 curriculum/structure/blocks/daily-coding-challenges-javascript.json 可以看到它归属于daily-coding-challenges-javascript模块block其顺序表中登记为{ id: 68ffb91507a5b645769328c6, title: Challenge 103: LCM }结合仓库中的 superblock 结构文件 curriculum/structure/superblocks/dev-playground.json可以推断该模块整体位于 Dev Playground 大模块之下作为每日一题的内容源。该 block 配置同时标记了isUpcomingChange: true、helpCategory: JavaScript、usesMultifileEditor: true等元信息说明这类挑战基于多文件编辑器运行、按 JavaScript 帮助分类。挑战文档自身的 frontmatter 则声明了challengeType: 28与dashedName: challenge-103其中dashedName会被用于拼装学习页面的路由标识前端代码中可见dashedName: challenge-${challengeNumber}的拼接逻辑见 client/src/client-only-routes/show-daily-coding-challenge.tsx。题目要求与 LCM 的数学定义原文档 --description-- 部分给出的任务陈述非常简洁Given two integers, return the least common multiple (LCM) of the two numbers.即给定两个整数返回它们的最小公倍数。文档同时对概念作了精确限定LCM 是同时为两个数倍数的最小正整数例如输入4和6返回12因为4的倍数依次为4、8、12、…6的倍数依次为6、12、18、…12是同时能被两者整除的最小数。这里的输入按文档措辞为两个整数integer因此题目实现需要留意负数的边界情形——这恰恰也是官方解法使用Math.abs的原因详见下文解法剖析。从 GCD 挑战到 LCM 挑战同一模块的知识递进值得注意的是第 103 题并非该模块中第一个数论题目。在模块顺序表中第 97 题正是 Challenge 97: GCDcurriculum/structure/blocks/daily-coding-challenges-javascript.json 中登记 id 为68f6587287ad1f4ad39b0c83。GCD 与 LCM 存在经典恒等关系lcm(a, b) × gcd(a, b) |a × b|因此求解 LCM 最常见的策略就是先求最大公约数再借助上式换算。这一递进设计让挑战者在连续几天内巩固数论算法官方给出的 LCM 解法也明确复用了 GCD 思路。判定标准五组断言与验证方式原文档的 --hints-- 部分给出了 5 个自动化断言即实现必须通过的全部测试用例调用期望返回验证要点lcm(4, 6)12基础互质因子组合4 与 6 的最大公约数为 2lcm(9, 6)18非互质但含较大质因子9 的质因子含 3²lcm(10, 100)100一个数为另一个数的倍数时LCM 等于较大者lcm(13, 17)221两个质数相乘验证互质情形下 LCM 即两数之积lcm(45, 70)630稍大整数的普适性验证这些断言在题目环境中会以类似下述代码执行原文 68ffb91507a5b645769328c6.md 的 hints 块assert.equal(lcm(4, 6), 12); assert.equal(lcm(9, 6), 18); assert.equal(lcm(10, 100), 100); assert.equal(lcm(13, 17), 221); assert.equal(lcm(45, 70), 630);其中10与100、13与17两组用例尤其值得注意前者覆盖了「成倍数关系」的退化情形后者覆盖了「两数互质」的边界情形是检验实现是否鲁棒的关键。从数据模型看这类挑战的测试在仓库中表示为{ text, testString }结构。校验器 client/src/utils/daily-coding-challenge-validator.ts 中定义了完整的结构约束每个挑战须包含id、challengeNumber不小于 1 的整数、title、date、description以及javascript、python两种语言的实现数据而每种语言数据内必须含有tests数组与challengeFiles数组。这意味着本题的hints会被转写为数据库中javascript.tests的若干条testString供在线编辑器逐条执行判定。从种子代码到官方解法种子代码题目初始框架原文档 --seed-- 提供的是带缺失逻辑的函数骨架function lcm(a, b) { return a; }学习者只需补全lcm的内部实现使函数最终返回两数的最小公倍数即可函数签名lcm(a, b)保持不动。官方解法欧几里得 GCD 乘积相除原文档 --solutions-- 给出的参考实现如下function lcm(a, b) { function gcd(x, y) { return y 0 ? x : gcd(y, x % y); } return Math.abs(a * b) / gcd(a, b); }这一实现可以拆成三个关键点逐层理解第一层内嵌递归求 GCD。gcd(x, y)采用经典的欧几里得算法辗转相除法若y为0则x即为最大公约数否则递归调用gcd(y, x % y)把除数与余数作为新一轮参数。例如求gcd(6, 4)x 6, y 4y ! 0递归gcd(4, 6 % 4 2)x 4, y 2y ! 0递归gcd(2, 4 % 2 0)x 2, y 0返回2。第二层借助恒等式lcm(a, b) × gcd(a, b) |a × b|换算。由于 LCM 与 GCD 的乘积恰好等于两数绝对值之积直接用两数乘积除以 GCD 即可得到 LCM无需暴力枚举倍数。第三层Math.abs(a * b)处理负数与符号问题。题目输入为整数可能出现负数。若不做绝对值处理负数的乘积除以 GCD 可能得到负数与「最小公倍数为正整数」的定义冲突同时若不先取绝对值符号会干扰整除语义的可读性。官方实现通过Math.abs保证最终结果为正值。以测试用例逐一手算验证lcm(4, 6)gcd(4, 6) 2|4 × 6| / 2 24 / 2 12✅lcm(9, 6)gcd(9, 6) 354 / 3 18✅lcm(10, 100)gcd(10, 100) 101000 / 10 100✅lcm(13, 17)互质gcd 1221 / 1 221✅lcm(45, 70)gcd(45, 70) 53150 / 5 630✅可见该实现可完整通过全部 5 个断言。延伸不使用 GCD 的替代实现路径除官方解法外LCM 还有若干等价实现思路可作为举一反三的练习方向下述为通用算法知识并非仓库内实现暴力递增法从两数中较大者开始每次增加较大者步长可设为max(a, b)检查是否能同时整除两数找到的第一个数即 LCM。思路直观但当输入较大时效率明显偏低。质因数分解法将两数分别质因数分解LCM 为各质因数取最高次幂之积。适合手工推导与教学演示但编码复杂度和运行时开销都高于欧几里得方案。基于 GCD 的库函数/内建函数在支持内建 GCD 的环境如 Python 的math.gcd中可直接套用同一恒等式。对比可见官方解法选用的「欧几里得递归求 GCD 乘积相除」在时间复杂度和代码简洁度上都是较优的选择——欧几里得算法的时间复杂度约为O(log(min(a, b)))远优于暴力枚举。源码级链路挑战文档如何变成每天一道的练习题理解题目本身之后沿着仓库源码可以看到这条挑战从「课程 Markdown」到「在线可做」的完整流转链路这有助于读者尤其是希望自定义挑战或参与课程贡献的开发者把握数据流第一步从 GraphQL 拉取挑战。seed 脚本 tools/daily-challenges/seed-daily-challenges.ts 会读取 MongoDB 环境变量MONGOHQ_URL默认mongodb://127.0.0.1:27017/freecodecamp?directConnectiontrue并期望恰好找到 365 道挑战脚本内EXPECTED_CHALLENGE_COUNT 365分别抓取 JavaScript 与 Python 两套实现fetchChallenges(javascript)与fetchChallenges(python)并校验两语言数量一致。第二步为挑战分配日期与编号。脚本从2025-08-11T00:00:00.000ZSTART_DATE起为第i道挑战追加i × 24 小时得到每天的发布日期challengeNumber依序从1编号到365。由此第 103 题在平台中对应一个具体日期前端按日期路由取题。执行方式与依赖关系在 tools/daily-challenges/README.md 中有说明运行前需先以「显示即将上线内容」的方式启动主客户端使 GraphQL 能查询到该模块再执行pnpm seed-daily-challenges将数据写入DailyCodingChallenges集合upsert 语义保证可重复执行。第三步入库数据的结构约束校验。写入数据库的每条记录其结构与 client/src/utils/daily-coding-challenge-validator.ts 中基于 Joi 定义的 schema 对齐挑战须有challengeNumber正整数、date日期字符串、description等字段javascript与python下又各含tests[{ text, testString }]与challengeFiles[{ fileKey, contents }]。LCM 题目的 5 条断言即以testString形式落库。第四步前端组装为经典挑战页面。client/src/client-only-routes/show-daily-coding-challenge.tsx 从数据库/API 取得挑战数据后将其补全为通用挑战组件ShowClassic所需的 propschallengeType在 JavaScript 侧为28superBlock: daily-coding-challenge并注入challengeFiles文件名为script、扩展名js、fileKeyscriptjs与tests。这就是学习者网页上看到题目描述、编辑器和测试按钮的数据来源。第五步端到端验证。Playwright 测试 e2e/daily-coding-challenge.spec.ts 用 mock 数据模拟 API 返回其结构与校验器 schema 完全一致例如tests内含testString: assert.strictEqual(true, true);验证页面在合法日期下能正常加载并能完成 JavaScript 与 Python 语言切换对非法日期则会重定向到归档页。这为「LCM 题目页可正常打开、测试可运行」提供了自动化的质量保障。本地验证建议若想亲自验证 LCM 实现无需启动整个平台直接将函数与断言放入任意支持 ES 的 JavaScript 运行环境即可。参考下面的最小自测写法仅作本地运行演示仓库只读勿修改课程文件function lcm(a, b) { function gcd(x, y) { return y 0 ? x : gcd(y, x % y); } return Math.abs(a * b) / gcd(a, b); } const cases [[4, 6, 12], [9, 6, 18], [10, 100, 100], [13, 17, 221], [45, 70, 630]]; for (const [a, b, expected] of cases) { const actual lcm(a, b); console.log(lcm(${a}, ${b}) ${actual} (期望 ${expected}) ${actual expected ? PASS : FAIL}); }运行后如 5 行全部输出PASS即代表实现与原文档的 5 个 hints 断言一致。也可顺手验证负数输入例如lcm(-4, 6)应仍返回12体会Math.abs存在的意义。小结Challenge 103: LCM 以一道简洁的数论函数题串联起了三个层面的知识最小公倍数的数学定义与测试驱动判定、欧几里得算法的递归实现与 LCM/GCD 恒等变换以及 freeCodeCamp 仓库中每日编程挑战从 Markdown 课程文件经 seed 脚本、MongoDB、schema 校验到前端做题页面的完整工程链路。读者既可以把它当作一道独立的算法小题练习递归与边界处理也可以顺着 tools/daily-challenges、client/src/utils/daily-coding-challenge-validator.ts 与 e2e/daily-coding-challenge.spec.ts 等文件深入了解一个大型开源学习平台如何批量管理并发布每日练习内容。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表