news 2026/9/10 2:26:20

freeCodeCamp 每日编码挑战 Challenge 84 “Infected“ 题解:指数传播与周期性修补的 JavaScript 模拟

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
freeCodeCamp 每日编码挑战 Challenge 84 “Infected“ 题解:指数传播与周期性修补的 JavaScript 模拟

freeCodeCamp 每日编码挑战 Challenge 84 "Infected" 题解:指数传播与周期性修补的 JavaScript 模拟

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

导读

本文围绕 freeCodeCamp 开源仓库中 JavaScript 每日编码挑战的第 84 道题 "Infected"(题目文件)展开:给定自蠕虫(internet worm)发布以来经过的天数,模拟"每天感染数翻倍、每第 3 天打补丁削减 20% 且向上取整"的动态过程,返回最终感染总数。读完本文,你将掌握题目规则、完整推导过程、官方解答的逐行解析、边界条件与复杂度分析,并了解这道题在 freeCodeCamp 课程体系中的定位与测试基建。

挑战背景:1988 年互联网蠕虫与指数增长模型

题目描述引用了一个真实历史事件:

On November 2nd, 1988, the first major internet worm was released, infecting about 10% of computers connected to the internet after only a day.

1988 年 11 月 2 日发布的首个大型互联网蠕虫(即历史上著名的 Morris 蠕虫),在一天之内感染了约 10% 接入互联网的计算机。题目正是以此为背景,将蠕虫的传播抽象为一个简洁的数学模型:

  • 第 0 天:第一台计算机被感染。
  • 此后每天:被感染计算机的数量翻倍。
  • 每第 3 天:病毒传播之后会应用一次补丁,将感染数削减 20%,削减的数量向上取整到最接近的整数(即对补丁数量Math.ceil,而不是对结果向下取整)。

这道题的核心价值在于:用一个简短的可迭代模拟,同时练习了指数增长取模判断周期Math.ceil向上取整三个 JavaScript 基础能力,是非常典型的 daily coding challenge 难度与风格。

题目规则与数学模型

需要实现一个函数infected(days),输入为经过的天数(非负整数),输出为经过该天数后总计仍处于感染状态的计算机数量。

规则的形式化表述如下:

  1. 初始条件:day === 0时感染数为1
  2. 传播阶段:从第 1 天起,每一天先执行infected *= 2
  3. 补丁阶段:若day % 3 === 0,则在传播完成后执行削减——补丁数量 =Math.ceil(infected * 0.2),然后infected -= patched

需要注意的关键细节:补丁是在当天病毒传播之后才应用的,因此第 3 天是先由第 2 天的 4 翻倍到 8,再削减;而不是先削减再翻倍。这一顺序直接决定了所有测试用例的结果。

官方逐步示例推导

题目给出了第 0~3 天的完整示例,逐日验证如下:

天数翻倍后感染数是否打补丁补丁数量(向上取整)当日结束后感染总数
Day 01(初始)1
Day 11 × 2 = 22
Day 22 × 2 = 44
Day 34 × 2 = 8是(3 % 3 === 0)8 × 20% = 1.6 →Math.ceil(1.6)= 28 − 2 = 6

其中第 3 天是理解本题的枢纽:8 * 0.2 = 1.6,向上取整得2,于是8 - 2 = 6。这里必须使用Math.ceil,如果误用Math.floorMath.round,结果会分别变成8 - 1 = 78 - 2 = 6Math.round(1.6)恰好也为 2,但其他天数会偏离),无法稳定通过全部测试。

种子代码与函数签名

题目提供的初始代码(--seed-contents--)如下,学习者需要补全函数体:

function infected(days) { return days; }

函数接收一个参数days(非负整数),返回数值类型的感染总数。题目没有要求处理负数或非整数输入——从测试用例看,入参均为1381725这样的非负整数。

测试用例一览

仓库题目文件中的--hints--部分给出了 5 个测试用例,它们既是指标,也是推导答案的依据:

assert.equal(infected(1), 2); assert.equal(infected(3), 6); assert.equal(infected(8), 152); assert.equal(infected(17), 39808); assert.equal(infected(25), 5217638);

逐条验证:

  • infected(1):第 1 天只翻倍不打补丁 →1 × 2 = 2
  • infected(3):如上表推导 →6
  • infected(8):在第 3、6 天各打一次补丁,连续迭代结果为152
  • infected(17):在第 3、6、9、12、15 天共打 5 次补丁,结果为39808
  • infected(25):补丁发生在 3、6、9、12、15、18、21、24 天共 8 次,最终为5,217,638

可以观察到:尽管每 3 天削减一次,但由于削减比例(20%)远小于翻倍比例(100%),感染数整体仍呈指数级上升——这正是题目想传达的"蠕虫传播的可怕速度"。

官方解答逐行解析

题目自带的--solutions--给出了参考实现:

function infected(days) { let infected = 1; for (let day = 1; day <= days; day++) { infected *= 2; if (day % 3 === 0) { let patched = Math.ceil(infected * 0.2); infected -= patched; } } return infected; }

逐行解读:

  1. let infected = 1;—— 对应"第 0 天第一台计算机被感染"的初始状态。
  2. for (let day = 1; day <= days; day++)—— 从第 1 天迭代到第days天,正好执行days次循环;当days === 0时循环体一次都不执行,直接返回1,与"第 0 天返回 1"的语义一致。
  3. infected *= 2;—— 每天先翻倍(传播阶段)。
  4. if (day % 3 === 0)—— 用取模判断"每第 3 天",覆盖第 3、6、9、12…天。
  5. let patched = Math.ceil(infected * 0.2);—— 补丁数量按当前感染数的 20% 计算并向上取整Math.ceil是本题最容易遗漏或误用的 API。
  6. infected -= patched;—— 削减感染数,进入下一天。

该实现的时间复杂度为 O(days),空间复杂度为 O(1),只需维护单个数字变量即可完成模拟,无需任何数组或额外数据结构。

常见陷阱

  • 取整方向错误:必须用Math.ceil。题目明确要求"Round the number of patched computers up to the nearest whole number"(将补丁数量向上取整),即补丁数偏多、削减更激进。
  • 补丁与翻倍的顺序:必须"先传播、后打补丁"。若颠倒顺序(如第 3 天先 4−补丁再翻倍),结果将完全不同。
  • 循环边界for (let day = 1; day <= days; day++)day < days相差一次循环,直接导致所有测试用例偏移一天。
  • 运算精度infected * 0.2会产生浮点数(如1.6),Math.ceil负责将其归一为整数;削减后infected应始终是整数。

变体与思考:Python 版本与扩展练习

freeCodeCamp 的每日编码挑战同时维护了 JavaScript 与 Python 两个版本(对应挑战类型dailyChallengeJs = 28dailyChallengePy = 29,见 challenge-types.ts)。如果你想用 Python 复现同一逻辑,思路完全一致,只是把取模与向上取整换成 Python 语法(如math.ceil);仓库的配对测试保证了两种语言版本在题目 ID、标题、描述与测试数量上完全一致。

此外可以自行扩展思考:

  • 若补丁改为每 4 天一次,感染数曲线如何变化?
  • 若削减比例改为 30%,infected(25)会变成多少?
  • 如果允许days很大(如 10^6),O(days) 是否仍然可行?能否推导出闭式公式?

该挑战在 freeCodeCamp 仓库中的工程定位

"Infected" 并非孤立题目,它在整个仓库中有完整的工程化支撑,这些结构可以帮助你理解每日编码挑战的运转方式:

  • 挑战文件本身:curriculum/challenges/english/blocks/daily-coding-challenges-javascript/68e39ed6106dac2f0a98fd66.md 采用 freeCodeCamp 标准的多段落 Markdown 格式:front-matter(idtitlechallengeTypedashedName)、--description----hints----seed----solutions--
  • 挑战类型challengeType: 28对应共享配置中的dailyChallengeJs(packages/shared/src/config/challenge-types.ts),其视图类型为classic,提交类型为tests——也就是说,学习者在经典编辑器中编写代码,由内置测试断言(即--hints--)判定是否通过。
  • 所属块(block)配置:daily-coding-challenges-javascript.json 表明该块使用多文件编辑器(usesMultifileEditor: true)、帮助分类为 JavaScript,并设置了disableLoopProtectTests: true(即不施加"循环保护"测试限制,允许自由使用for循环)——这正是本解答可以放心使用for循环的工程依据。
  • Schema 校验:challenge-schema.js 要求challengeType0~33的整数,28 在其合法范围内,保证此类题目的元数据合法性。
  • 每日挑战 API:前端通过 daily-coding-challenge 路由 获取每日题目,提供/daily-coding-challenge/date/:date/day/:day/today/month/:month/all/newest等公开 GET 端点,响应 schema 见 schemas/daily-coding-challenge.ts。
  • 配对测试:daily-challenges.test.js 会分别加载 JavaScript 与 Python 每日挑战,断言两者数量一致,且同序号题目的 ID、标题、描述与测试数量完全匹配,保证两种语言版本同步维护。

如果你想在本地查看这道题,只需阅读上述题目文件即可;若想运行其测试,可参考 curriculum/src/test 下的 Vitest 配置与测试工具链(test-challenges.jsvitest.config.mjs)了解如何按 block 加载并校验挑战。

小结

Challenge 84 "Infected" 是一道小而精的模拟题:用for循环驱动指数增长,用% 3触发周期性补丁,用Math.ceil处理向上取整。它的工程价值不仅在于练习三个基础语法点,更在于让你体会"以文档规则为唯一事实来源"的解题方式——题目描述、测试用例与官方解答三者互相印证,构成了 freeCodeCamp 每日编码挑战可自动化判定的完整闭环。

【免费下载链接】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:25:39

用 Automator 在访达中一键新建文件:右键快速操作全攻略

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

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

Python CSV读写完全指南:标准库、pandas与编码避坑

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

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

基于LabVIEW的分布式四驱扭矩主动分配测控系统实战解析

简介&#xff1a;基于LabVIEW的汽车扭矩主动分配测控系统是一份源自全国虚拟仪器大赛的完整工程方案&#xff0c;面向测控、汽车电子方向的工程师与学习者&#xff0c;解决驱动轮扭矩实时分配与车辆稳定性控制问题。压缩包内共5个文件&#xff0c;包含Simulink模型&#xff08;…

作者头像 李华