FEATURED · 精选文章

freeCodeCamp「每日编程挑战」Space Week 第 3 天实战解析:用 reduce 计算深空消息传输耗时(Challenge 57: Phone Home)

发布时间 / 2026/9/10 23:34:53
来源 / 创域科博编辑部
栏目 / 资讯中心
freeCodeCamp「每日编程挑战」Space Week 第 3 天实战解析:用 reduce 计算深空消息传输耗时(Challenge 57: Phone Home) freeCodeCamp「每日编程挑战」Space Week 第 3 天实战解析用 reduce 计算深空消息传输耗时Challenge 57: Phone Home【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本篇文章是 freeCodeCamp 开源课程「每日编程挑战」系列中Challenge 57: Space Week Day 3: Phone Home的完整技术解析。通过这一道以“深空通信链路时延计算”为故事背景的算法题你将掌握如何把现实中的物理约束翻译成数组累加、固定延迟与时间换算逻辑并用toFixed与Number精确控制浮点输出格式最终得到一份可通过全部单元测试的 JavaScript 参考解法。读完本文你既能独立完成这道挑战也能理解它在 freeCodeCamp 仓库中从 Markdown 题目文件到数据库种子脚本的完整生命周期。题目出处与定位这道题存放在课程的英文题库中其 Markdown 源文件位于 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68c1a929005bf54d342aa8d4.mdfrontmatter 中记录了它的元数据字段值id68c1a929005bf54d342aa8d4titleChallenge 57: Space Week Day 3: Phone HomechallengeType28dashedNamechallenge-57它是 “Space Week”太空周主题系列的第 3 题。从块block的结构清单 curriculum/structure/blocks/daily-coding-challenges-javascript.json 可以看出challengeOrder中 Challenge 55 到 61 连续组成了这一周的主题挑战Day 1Stellar Classification恒星分类、Day 2Exoplanet Search系外行星搜索、Day 3Phone Home本次题目、Day 4Landing Spot着陆点、Day 5Goldilocks Zone宜居带、Day 6Moon Phase月相、Day 7Launch Fuel发射燃料。该块同时设置了usesMultifileEditor: true、helpCategory: JavaScript、disableLoopProtectTests: true等元信息说明它属于课程体系中标记为isUpcomingChange: true的实验性每日一练模块。题目要求把通信链路翻译成数组故事背景Space Week 第 3 天你身处深空。你收到的输入是一个数字数组数组中的每个元素代表通信链路上某一段链路的距离单位千米。链路从“你所在位置”出发依次经过若干颗中继卫星最终抵达你的“母星”。题目要求你计算一条消息沿这条链路传输到母星总共需要多少秒。数组结构与语义约束题目明确给出四条约束它们共同定义了数组route的物理含义route的第一个值从你的位置到第一颗卫星的距离除最后一个值外的每个后续值从前一颗卫星到下一颗卫星的距离route的最后一个值从倒数第二颗卫星到你的母星的距离消息传播速度为300,000 km/s即光速量级题目取整为 30 万。因此对于一个长度为 n 的数组数组里一共有 n 段距离每段距离都参与一次“距离 ÷ 速度”的纯传播时间计算而数组元素之间共有n - 1 个边界点也就是消息“经过”的中继卫星个数。题目规定每经过一颗卫星额外增加 0.5 秒的转发延迟。也就是说卫星数量 route.length - 1。这是整个模型最关键的地方很多人会误把“数组元素个数”当作卫星数量导致延迟算错。输出格式要求返回值是一个数字要求四舍五入到小数点后 4 位去掉末尾多余的零trailing zeros removed。“去掉尾零”意味着最终答案在类型上应该是number而非“固定四位小数字符串”例如2.5而不是2.5000364.5而不是364.5000。这一点直接决定了收尾阶段该用哪些 API。解题思路逐步拆解整个过程可以分成三步逻辑非常清晰累加总距离把数组所有元素求和得到整条链路的总里程totalDistance计算纯传播时间用总距离 ÷ 300000得到光速传播耗时time叠加转发延迟route.length - 1颗卫星每颗 0.5 秒即延迟delay (route.length - 1) * 0.5最终total time delay。收尾时对total执行四舍五入到 4 位并去掉尾零。唯一需要小心的是输出要求Number(total.toFixed(4))能同时做到“四舍五入”与“数值化去尾零”。下面我们用第一个测试样例手动验证模型sendMessage([300000, 300000])。数组长度为 2包含两段距离你 → 卫星 300,000 km卫星 → 母星 300,000 km总距离 600,000 km纯传播时间 600,000 ÷ 300,000 2 秒经过的中继卫星 2 - 1 1 颗延迟 0.5 秒总耗时 2 0.5 2.5 秒与断言一致。参考解决方案逐行解读# --solutions--部分提供了官方参考实现这里结合逐行注释展开function sendMessage(route) { // 1. 累加整条链路所有分段的总距离 let totalDistance route.reduce((a, d) (a d), 0); // 2. 转发延迟数组有 length 个分段卫星位于分段之间共 length - 1 颗 const delay (route.length - 1) * 0.5; // 3. 纯传播时间距离 ÷ 速度300,000 km/s const time totalDistance / 300000; // 4. 相加得到总耗时四舍五入到 4 位小数并用 Number 移除尾零 const total time delay; return Number(total.toFixed(4)); }第 1 步reduce累加总距离route.reduce((a, d) (a d), 0)以0为累加初值把数组内所有距离累加为totalDistance。这里需要留意的是箭头函数体内使用了赋值表达式a d并把赋值结果返回写成更常规的route.reduce((a, d) a d, 0)在语义上完全等价且更不易混淆。reduce是 ES5 就引入的数组方法在浏览器与 Node 环境中都能直接使用。第 2 步卫星转发延迟的边界数量数组元素个数 n 代表链路被切成 n 段中继卫星恰好落在段与段之间因此卫星数量是n - 1而不是 n。例如[300000, 300000]有两个元素但只有 1 颗卫星。题目原文 “Each satellite the message passes through adds a 0.5 second transmission delay” 中的passes through一词提示起点与终点并不算“经过”只有中间节点才算这与(route.length - 1) * 0.5一一对应。第 3 步传播速度常量300000即题目给定的 300,000 km/s。在真实深空通信场景中这个数字对应光速量级——光从月球到地球约需 1.3 秒从火星到地球约需数分钟到数十分钟这也是本题“母星—卫星—你”设定中取值如此巨大的原因。第 4 步toFixed(4)与Number的去尾零魔法这一步是整个题目的“输出陷阱”所在total.toFixed(4)把数字四舍五入成固定 4 位小数的字符串如2.5000、3.0627直接返回字符串不满足题意题目要求2.5而非2.5000因此外层再用Number()把它转回数字类型尾零自然被去除例如Number(2.5000) 2.5、Number(3.0627) 3.0627、Number(364.5000) 364.5。用 6 个断言反推实现细节题目的# --hints--部分给出了 6 条assert.equal测试断言它们不仅是评分依据更是一组精心设计的边界样例能帮你反向确认每一步算法的正确性。下面逐一验算保留 4 位小数输入route总距离 (km)纯传播时间 (s)卫星数 n-1转发延迟 (s)总计 (s)断言期望[300000, 300000]600,000210.52.52.5[384400, 384400]768,8002.562666…10.53.062666…3.0627[54600000, 54600000]109,200,00036410.5364.5364.5[1000000, 500000000, 1000000]502,000,0001673.333333…211674.333333…1674.3333[10000, 21339, 50000, 31243, 10000]122,5820.408606…422.408606…2.4086[802101, 725994, 112808, 3625770, 481239]5,747,91219.159706…4221.159706…21.1597这些样例在验证什么整除与非整除的混合。第一、三组数据中的距离恰好能被 30 万整除传播时间是整数秒2 和 364测试的是“浮点计算干净时输出不带小数噪声”第二、四、五、六组则产生无限循环小数如2.562666…、1673.3333…用来检验toFixed的四舍五入行为是否符合“4 位小数”约定。卫星数量取 n-1。最后一组[802101, 725994, 112808, 3625770, 481239]长度是 5如果误把延迟算成5 × 0.5 2.5秒结果会是21.6597…与期望值21.1597相差恰好 0.5 秒——这正是“卫星数 n - 1 4”最直接的判据。去尾零。期望值写作2.5、364.5、3.0627而非2.5000之类直接要求实现用Number()收尾而不是直接return total.toFixed(4)。常见误区与浮点输出细节卫星数量数错把数组长度直接当卫星数导致多算 0.5 秒。记住模型元素之间有几条“缝”就有几颗卫星即length - 1。单位混淆距离单位是千米、速度单位是千米/秒两者相除得到的是秒无需再做任何单位或 60 进制换算。直接返回字符串toFixed返回字符串assert.equal严格断言下2.5 2.5不成立Number()转换是去掉尾零的关键。自己实现“去尾零”用字符串replace或parseFloat也能达到效果但官方解法的Number(total.toFixed(4))最简洁、可读性最好。reduce初值遗漏显式传入0作初值是更稳妥的写法可避免对空数组或首元素行为的不确定性。浮点噪声JS 中0.1 0.2 ! 0.3这类问题在本例中由“求和后再一次性toFixed(4)”规避切记不要对中间结果过早取整否则累计误差可能让最终第 4 位小数偏移。挑战文件到线上题库它在仓库中如何流转这道题的.md文件并不直接驱动线上运行而是经历了从“课程源文件”到“每日挑战数据库文档”的管道理解这条链路能帮你更准确地把握题目形态。挑战源文件结构freeCodeCamp 的每个挑战 Markdown 都遵循统一的分节约定---之间的 YAML frontmatter记录id、title、challengeType、dashedName# --description--题目描述与约束# --hints--以assert形式书写的单元测试每条测试有面向学员的文本描述和可执行的 JS 断言# --seed--## --seed-contents--学员编辑器中预置的起始代码骨架即只return route的sendMessage函数# --solutions--官方参考实现供解析与校对流程使用。本题骨架文件给出的是function sendMessage(route) { return route; }这是一个“占位返回”保证函数在学员动手前即可被调用测试不会因函数未定义而直接崩溃。种子脚本如何把挑战灌入数据库tools/daily-challenges/README.md 描述了每日挑战的入库流程脚本通过运行中的 Gatsby 客户端 GraphQL 端点抓取“Dev Playground”超级块下daily-coding-challenges-javascript与 Python 版的挑战再写入 MongoDB 的DailyCodingChallenges集合。核心逻辑在 tools/daily-challenges/helpers.tsqueryGraphQL向本地 GraphQL 端点发起请求并校验allChallengeNode.edges是否为空否则抛出 “The client needs to be running” 的报错——可见本地必须先把主客户端跑起来才能完成抓取fetchChallenges(javascript)以superBlock: dev-playground、block: daily-coding-challenges-javascript为过滤条件、按challengeOrder: ASC排序取回id/title/description/tests/challengeFilescombineChallenges校验 JS 与 Python 两个版本的标题、描述、测试数量必须一致随后以 JS 挑战的id作为 MongoDB_id注释特别强调不要修改该 ID因为它会被写入用户画像的completedDailyCodingChallenges[]并将测试与初始代码按javascript/python两个语言字段分别存库。数据库文档的结构校验逻辑可参见 api/src/daily-coding-challenge/README.md客户端侧的 Joi 校验器位于 client/src/utils/daily-coding-challenge-validator.ts每个挑战文档需要id、整数challengeNumber、title、date、description以及分别包含tests每项有text与testString和challengeFiles每项有fileKey与contents的javascript/python两个对象。这与本挑战源文件中--hints--映射为 tests与--seed-contents--映射为 challengeFiles的分节一一呼应。也就是说Challenge 57 这类题目的--description--、--hints--、--seed--之所以要严格遵守“结构化分节”的写法正是因为下游种子脚本、API Schema 与客户端校验器都在按这些分节各取所需。学员在 web 端提交代码后服务端会用tests[].testString里那条assert.equal(sendMessage(...), ...)对学员函数求值来判断是否通关。延伸思考进一步改写的可能方向从参考解出发可以做不少练习与变体很适合加深对这道题的理解循环改写不使用reduce改用for...of或forEach累加确认对“延迟 长度 - 1”的理解不受累加方式影响原地拆解把“总传播时间”和“转发延迟”分离成两个纯函数再组合方便为两部分分别写单元测试健壮性增强思考route长度为 0 或 1 时的行为例如长度为 1 时没有卫星(1 - 1) * 0.5 0公式依然自洽常量化把300000与0.5提取为命名常量如const SPEED_OF_LIGHT_KMS 300000提升代码自解释性——这也契合 freeCodeCamp 一贯强调的可读性编程风格。小结Challenge 57: Phone Home 是一道“物理故事 数组处理 格式化输出”三位一体的入门级算法题它要求你把“每颗卫星 0.5 秒延迟”“消息以光速传播”等文字约束精确转译为reduce求和、(length - 1) * 0.5与total / 300000的算术表达式并借助Number(total.toFixed(4))同时满足“四舍五入 4 位”与“去除尾零”两个输出约束。想要验证自己的实现可以对照本文的 6 组验算表逐条跑断言想要深入了解它的运行环境可以继续研读 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68c1a929005bf54d342aa8d4.md 的完整题目分节、curriculum/structure/blocks/daily-coding-challenges-javascript.json 的块元数据以及 tools/daily-challenges/helpers.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),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻