freeCodeCamp 每日编程挑战解析:Challenge 282「Sleep Debt」睡眠债计算
freeCodeCamp 每日编程挑战解析Challenge 282「Sleep Debt」睡眠债计算【免费下载链接】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-javascript 块的 Challenge 282「Sleep Debt」为核心完整讲解题目要求、5 组判题用例、逐步解题思路与官方单行题解并结合仓库中的种子脚本、校验器与 API 路由还原一道每日挑战从 Markdown 文件到在线判题的完整生命周期。读完你将掌握数组聚合与「包含今晚在内的补债总额」这类边界语义的建模方法也能理解 freeCodeCamp 每日挑战系统的运行机制。一、挑战背景Daily Coding Challenge 与 Challenge 282 的定位「Sleep Debt」是 freeCodeCamp 每日编程挑战Daily Coding Challenge系列的第 282 道题目原始 Markdown 文件位于 curriculum/challenges/english/blocks/daily-coding-challenges-javascript/69f35a5bb823ed620fcb7cbb.md题目文件头frontmatter定义如下id: 69f35a5bb823ed620fcb7cbb title: Challenge 282: Sleep Debt challengeType: 28 dashedName: challenge-282在块结构文件 daily-coding-challenges-javascript.json 中可以看到该块的完整配置dashedName为daily-coding-challenges-javascript与 Python 版daily-coding-challenges-python一一对应两道语言版本的题目 ID、标题、描述必须完全一致由 daily-challenges.test.js 的测试用例强制约束helpCategory为JavaScriptblockLayout为legacy-challenge-listchallengeType: 28是每日挑战专用的类型编号同一块内共有 365 道题见种子脚本EXPECTED_CHALLENGE_COUNT 365Challenge 282 在challengeOrder中排在Challenge 281: Bingo Range之后、Challenge 283: String Zipper之前。二、题目要求解析题目描述--description--部分原文如下Given an array of hours slept each night leading up to today, and a target number of hours per night, return how many hours of sleep you need tonight to eliminate your sleep debt.即给定「截至今天为止每一晚的睡眠小时数」数组hoursSlept以及「每晚目标睡眠小时数」targetHours返回今晚需要睡多少小时才能还清全部睡眠债。函数签名种子代码--seed--为function sleepDebt(hoursSlept, targetHours) { return hoursSlept; }题目附带两条必须满足的语义约束把今晚的睡眠时间计入补债所需的总时间——即补债不是「缺多少补多少」而是「还清过去所有欠账 今晚本身的目标」都要靠今晚这一觉来完成如果过去的总睡眠已经覆盖了今晚的目标甚至更多则返回0——睡眠债不可能是负数睡多了不会产生「负债」。理解这两条规则是解出此题的关键它把问题从简单的「差值求和」变成了「以(过去天数 1)晚为总基准的差额计算」。三、测试用例与期望输出题目共给出 5 组判题用例--hints--部分这里逐一演算帮助你校准对规则的理解输入hoursSlept输入targetHours期望返回值演算过程[6, 6, 6, 6, 6, 6]820过去 6 晚共睡 36 小时算上今晚共 7 晚基准 7 × 8 56差额 56 − 36 20[6, 7, 8, 4, 8, 6]710过去共睡 39 小时7 晚基准 49差额 49 − 39 10[10, 10, 9, 10, 9, 11]94过去共睡 59 小时7 晚基准 63差额 63 − 59 4[8, 7, 6, 7, 6, 8]60过去共睡 42 小时7 晚基准 42差额 0恰好还清返回 0[8, 9, 10, 9, 10, 7]70过去共睡 53 小时7 晚基准 49差额 −4已超额按规则返回 0对应仓库中的断言代码为assert.equal(sleepDebt([6, 6, 6, 6, 6, 6], 8), 20); assert.equal(sleepDebt([6, 7, 8, 4, 8, 6], 7), 10); assert.equal(sleepDebt([10, 10, 9, 10, 9, 11], 9), 4); assert.equal(sleepDebt([8, 7, 6, 7, 6, 8], 6), 0); assert.equal(sleepDebt([8, 9, 10, 9, 10, 7], 7), 0);注意最后两组用例一组恰好持平、一组已经超标二者都必须返回0这正是规则二「睡眠债不为负」的体现。四、从零到一的解题思路按题目语义可以拆解为三步第一步计算过去所有夜晚的睡眠总时长。使用Array.prototype.reduce对数组求和const totalSlept hoursSlept.reduce((sum, h) sum h, 0);第二步确定包含今晚在内的总基准。数组长度hoursSlept.length代表过去的天数加上今晚这一晚总天数应为hoursSlept.length 1基准目标为const target (hoursSlept.length 1) * targetHours;这里的 1正是题目规则「Include tonights hours in the total time needed to catch up」的直接体现也是最容易被忽略的一处。第三步求差额并钳制为非负。差额 基准 − 已睡总量。若差额为负已超额返回 0const debt target - totalSlept; return Math.max(0, debt);完整实现function sleepDebt(hoursSlept, targetHours) { const totalSlept hoursSlept.reduce((sum, h) sum h, 0); const target (hoursSlept.length 1) * targetHours; return Math.max(0, target - totalSlept); }五、官方题解深度剖析题目--solutions--部分给出的官方参考实现只有两行function sleepDebt(hoursSlept, targetHours) { const debt (hoursSlept.length 1) * targetHours - hoursSlept.reduce((sum, h) sum h, 0); return Math.max(0, debt); }逐段解读(hoursSlept.length 1) * targetHours把「过去n晚 今晚」统一折算成总目标时长length 1与题目第一条例外规则严格对应hoursSlept.reduce((sum, h) sum h, 0)一次遍历完成全量求和初始值为0避免了对空数组的NaN风险reduce对空数组且无初始值会抛TypeErrorMath.max(0, debt)将差额钳制在0以上一次性同时处理「恰好还清」与「已经超额」两种边界与题目第二条规则完全一致。时间复杂度为 O(n)一次reduce遍历空间复杂度为 O(1)只用一个中间变量。整道题是「数组聚合 数学语义建模 边界钳制」三个知识点的最小组合非常适合作为 reduce 与 Math 工具函数的入门练习题。可读性改进版本官方解将全部逻辑压缩在一行表达式中可读性稍弱。若追求清晰可将基准目标与差额拆成两步语义更直观function sleepDebt(hoursSlept, targetHours) { const nights hoursSlept.length 1; // 过去 n 晚 今晚 const targetTotal nights * targetHours; // 还清债务所需的总额 const actualTotal hoursSlept.reduce((a, b) a b, 0); return Math.max(0, targetTotal - actualTotal); // 债务不为负 }六、边界情况与易错点忘记 1若只按hoursSlept.length * targetHours计算基准用例 1 会得到48 − 36 12而非20直接判错。 1是本题与「普通补差」类题目的本质区别负数债务Math.max(0, debt)之前debt可能是负数用例 5 为 −4。缺少钳制会导致返回负数违反题目第二条规则数组全为 0 的极端情况如sleepDebt([0, 0, 0, 0, 0, 0], 8)基准为 56已睡 0 小时应返回 56——即「今晚要睡满 8 小时来补上过去的欠账 今晚的 8 小时」浮点输入虽然用例均为整数但该实现同样适用于小数小时数如7.5Math.max与reduce均与数值类型无关。七、挑战在系统中的生命周期从 Markdown 到在线判题理解了算法本身后再看这道题目文件如何被 freeCodeCamp 的每日挑战管线消费能更完整地掌握这套体系。1. 文件结构与校验器每个挑战 Markdown 由 frontmatter、--description--、--hints--、--seed--、--solutions--五部分组成。前端读取数据库中的每日挑战时会通过 client/src/utils/daily-coding-challenge-validator.ts 中的 Joi schema 进行校验要求每个语言版本javascript/python都包含tests由text与testString组成和challengeFilesfileKeycontents。Challenge 282 文件中的 5 个assert断言最终就会进入testString字段成为在线判题器实际执行的测试代码。2. 种子脚本写入数据库tools/daily-challenges/seed-daily-challenges.ts 负责把 365 道每日挑战批量写入 MongoDB 的DailyCodingChallenges集合起始日期硬编码为2025-08-11T00:00:00.000Z之后每天递增一天ONE_DAY_IN_MS 24 * 60 * 60 * 1000最后一道365 号落在 2026 年 8 月 10 日前后脚本通过 GraphQL 从客户端查询dev-playground超块下的daily-coding-challenges-javascript与daily-coding-challenges-python两个块见 helpers.ts 中的fetchChallenges并校验两个语言版本的数量、标题、描述、测试数量完全一致写入时使用replaceOneupsert的批量操作ID 取自 JS 版本挑战的id即 Challenge 282 的69f35a5bb823ed620fcb7cbb该 ID 同时也是用户完成记录completedDailyCodingChallenges[]的关联键combineChallenges中有明确注释「DO NOT CHANGE THE ID」。按此机制推算Challenge 282索引 281对应的发布日期约为2026 年 5 月 19 日。3. API 端点按日期获取题目api/src/daily-coding-challenge/routes/daily-coding-challenge.ts 提供了若干公开 GET 路由供客户端拉取题目路由说明GET /daily-coding-challenge/date/:date按YYYY-MM-DD获取某天题目晚于美国中部时间当天的题目返回 404GET /daily-coding-challenge/day/:day按MM-DD不跨年获取GET /daily-coding-challenge/today获取今天美国中部时区的题目GET /daily-coding-challenge/month/:month按YYYY-MM返回当月题目列表仅 id、challengeNumber、date、titleGET /daily-coding-challenge/all返回全部已发布题目列表GET /daily-coding-challenge/newest返回最新题目的日期所有查询都会过滤date 今天US Central保证题目不会提前泄露路由内还埋有 Sentry 指标埋点如dcc.challenge_viewed、dcc.challenge_not_found用于观测使用情况。4. 判题与双语言一致性题目提交仍走主挑战完成路由README 中注明「Daily challenge submission still lives in the main part of the API」见 api/src/daily-coding-challenge/README.md。而 curriculum/src/test/daily-challenges.test.js 中的测试会断言 JS 与 Python 两个块「挑战数量一致」「ID 一一对应」「标题与描述一致」「测试数量一致」确保同一道题在两个语言版本下体验完全等价。八、延伸练习与变体掌握「Sleep Debt」的模型后可以尝试以下变体巩固同类思维平均睡眠债返回还清债务所需的平均每晚睡眠小时数debt / (length 1)考察除法精度与取整策略带权重的目标工作日与周末目标不同需要把targetHours改为数组并逐项求和考察reduce的多参数用法滚动窗口给定最近 30 天的记录只计算最近 7 天的睡眠债考察数组切片slice与聚合的组合返回明细同时返回{ debt, nightsNeeded }对象考察返回值结构设计。这些变体都能复用本挑战「基准总额 − 实际总额 − 非负钳制」的核心框架是练习数组聚合与边界建模的良好素材。参考资料Challenge 282 原始 Markdown 文件daily-coding-challenges-javascript 块结构定义每日挑战种子脚本 与 种子辅助函数每日挑战 API 路由前端每日挑战数据校验器双语言一致性测试【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考