ARTICLE DETAIL

资讯详情

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

freeCodeCamp 每日编程挑战深度解析:Challenge 133 “Daylight Hours“ 用查找表估算冬至日照时长

freeCodeCamp 每日编程挑战深度解析:Challenge 133 “Daylight Hours“ 用查找表估算冬至日照时长 freeCodeCamp 每日编程挑战深度解析Challenge 133 Daylight Hours 用查找表估算冬至日照时长【免费下载链接】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 Challenge每日编程挑战第 133 题 Daylight Hours它要求根据纬度值通过一张近似日照时长对照表估算 12 月 21 日冬至当天的日照小时数并学会用最邻近表项匹配处理表中没有的纬度。你将读到题目的完整数据表、JavaScript 与 Python 双版本参考解法的逐行原理、全部 8 个测试断言的判定逻辑以及这一题目在仓库中从课程 Markdown 到入库发布、再到前端渲染的完整工程链路。挑战背景这是免费编程课程中的一道每日算法题Daylight Hours 属于 freeCodeCamp 课程结构中dev-playground每日编程挑战实验区超级块下的 JavaScript 与 Python 两个 block在仓库中的位置为JavaScript 版curriculum/challenges/english/blocks/daily-coding-challenges-javascript/691f7773cddba1caf1bf5ecc.mdPython 版curriculum/challenges/english/blocks/daily-coding-challenges-python/691f7773cddba1caf1bf5ecc.md两个文件使用完全相同的问题编号id: 691f7773cddba1caf1bf5ecc与题目文本Challenge 133: Daylight Hours仅通过challengeType区分语言环境JavaScript 版为challengeType: 28Python 版为challengeType: 29该映射同样体现在客户端 client/src/redux/prop-types.ts 的类型定义challengeType: 28 | 29中。从 block 元数据 curriculum/structure/blocks/daily-coding-challenges-javascript.json 可以看到该 block 的challengeOrder中登记了本道题及其编号helpCategory为JavaScript并使用多文件编辑器usesMultifileEditor: true。这说明它属于每天推送给学习者一题的每日编程挑战系列系列共 365 题对应全年每一天而本文这道题是其中的第 133 题。题目目标按纬度估算冬至日照时长题面给出的现实背景是12 月 21 日是北半球的冬至winter solstice、南半球的夏至summer solstice。也就是说这一天北半球日照最短、南半球日照最长。题目要求给定一个-90 到 90 之间的纬度数值返回该纬度在冬至当天的日照时长近似值查询依据为以下对照表| Latitude纬度 | Daylight Hours日照小时数 | | - | - | | -90 | 24 | | -75 | 23 | | -60 | 21 | | -45 | 15 | | -30 | 13 | | -15 | 12 | | 0 | 12 | | 15 | 11 | | 30 | 10 | | 45 | 9 | | 60 | 6 | | 75 | 2 | | 90 | 0 |数据本身是符合地理直觉的南半球高纬度负值大接近极昼日照长达 24 小时北半球高纬度正值大接近极夜日照接近 0 小时赤道0°全年日照稳定在约 12 小时。题目补充了一条唯一的附加规则如果给定纬度无法在表中精确匹配就使用与之最接近的纬度表项所对应的日照小时数。例如45命中表项返回9而23处于15与30之间距两者各 8规则要求取最近的表项因此返回30对应的10小时。从种子代码出发函数骨架与输入约束题目在每个挑战文件末尾的# --seed--段中提供了统一的函数骨架学习者需要在浏览器多文件编辑器中补全函数体function daylightHours(latitude) { return latitude; }Python 版骨架使用蛇形命名def daylight_hours(latitude): return latitude需要特别注意的输入边界约束可由 tools/daily-challenges/types.ts 中声明的挑战数据模型结合题面推断latitude为-90 到 90 之间的整数测试数据均在该闭区间内题目不要求对区间外输入做异常处理也不要求输出中间态——只需返回最终小时数返回值是整数小时9、12、24等不需要像夏令时那样做小数近似。解题思路从条件判断链到查找表 最近邻匹配这道题有两条截然不同的实现路线官方参考解法选择的是更具工程价值的第二种。路线一穷举式条件判断既然只有 13 个离散档位且输入为整数最直接的做法是一长串if / else if区间判断。但这种写法本质上是把查找表硬编码进了分支结构代码冗长、难以维护且区间边界例如输入 15 与 16 之间的分界点在哪里极易写错。路线二查找表 最近邻扫描官方解法思路更稳健的思路分两步建模把对照表组织为一系列{ 纬度, 小时数 }记录作为数据与逻辑分离的查找表匹配线性扫描所有表项用Math.abs(表项纬度 - 输入纬度)计算距离始终记录当前距离最小的表项扫描结束后返回该表项的日照小时数。从实现原理看这其实就是一维空间中的最近邻查询nearest neighbor search查找表纬度已按从小到大排列属于单调递增的基准点序列而题目的距离度量就是数轴上的绝对差。官方参考解法源码逐行拆解题目自带的参考解法位于 Markdown 的# --solutions--段如下function daylightHours(latitude) { const table [ { lat: -90, hours: 24 }, { lat: -75, hours: 23 }, { lat: -60, hours: 21 }, { lat: -45, hours: 15 }, { lat: -30, hours: 13 }, { lat: -15, hours: 12 }, { lat: 0, hours: 12 }, { lat: 15, hours: 11 }, { lat: 30, hours: 10 }, { lat: 45, hours: 9 }, { lat: 60, hours: 6 }, { lat: 75, hours: 2 }, { lat: 90, hours: 0 } ]; let closest table[0]; for (const entry of table) { if (Math.abs(entry.lat - latitude) Math.abs(closest.lat - latitude)) { closest entry; } } return closest.hours; }关键点一以当前最优而非全局判定完成收敛let closest table[0]先假设第一个表项-90 → 24h就是最优随后循环中用**严格小于**比较当前候选与既有最优的距离。整个扫描过程与打擂台求最值算法同构只是比较的量从元素本身换成了|lat - latitude|。关键点二平局tie时的行为由于采用严格小于Math.abs(entry.lat - latitude) Math.abs(closest.lat - latitude)当两个相邻表项与输入纬度距离完全相等时closest不会被更新保留先遇到的那个。在本题目中表项以 15° 为间隔排列两相邻档位的中点必然落在x.5这类非整数上如 0 与 15 的中点是 7.5而输入纬度限定为整数因此整数输入永远不会踩中平局点先到先得与否不影响结果。即便如此选用严格小于仍然是一种值得保留的防御性写法。关键点三复杂度与可扩展性表共 13 项线性扫描的时间复杂度为 O(n)空间复杂度 O(1)表本身可视为常量数据。若表项数庞大且有序还可进一步用二分查找定位区间再做两端比较但在本题量级下线性扫描是最清晰直观的答案。测试即规范8 条断言逐条解读该挑战没有冗长的文档化规格测试断言本身就是需求的权威定义。8 条assert.equalPython 版等价为TestCase().assertEqual覆盖了精确命中、南北半球中间值、边界与最近邻四类场景测试调用期望值覆盖场景daylightHours(45)9表中精确命中daylightHours(0)12赤道精确命中daylightHours(-90)24南极极昼边界daylightHours(-10)12介于 -15 与 0 之间就近取 -15/0 的 12hdaylightHours(23)10介于 15 与 30 之间就近取 30 的 10hdaylightHours(88)0邻近北极点就近取 90 的 0hdaylightHours(-33)13介于 -30 与 -45 之间就近取 -30 的 13hdaylightHours(70)2介于 60 与 75 之间就近取 75 的 2h其中23、70、88、-33、-10这几组输入全部没有对应的精确表项正是用来强制验证使用最接近纬度这一规则的。可以手推验证23距 15 与 30 均为 8按严格更近才替换规则结果取先出现的——closest从table[0]-90一路推进扫描到 15 时距离 8 先被记录为最优到 30 时距离也是 88 8为假故不更新最终应返回15档的 11h……这里需要谨慎我们逐条核对后会发现23距15为 8距30为 8距离相等而题面要求的是最接近。为厘清平局语义请以仓库中该挑战的官方 Python 参考解法为准它使用abs(lat - latitude) abs(closest_lat - latitude)的严格小于比较与 JS 版一致地保留先扫描到的表项。需要说明的是参考解法的平局行为对全部 8 个整数测试输入均能给出正确结果——因为真正的平局点都落在.5小数纬度上例如 0° 与 15° 的中点为 7.5°整数输入无法命中。所有测试中最能体现就近匹配的是daylightHours(-10) → 12-10 介于 -1512h与 012h之间两侧恰好同值返回 12 无歧义。Python 双版本对照同一题目、同一算法、同一断言每日编程挑战刻意让 JS 与 Python 两个 block 保持题目文本、测试条数、期望结果完全一致种子脚本 tools/daily-challenges/helpers.ts 中甚至会在两语言标题、描述或测试数量不一致时直接抛错中断。Python 官方解法如下def daylight_hours(latitude): table [ (-90, 24), (-75, 23), (-60, 21), (-45, 15), (-30, 13), (-15, 12), (0, 12), (15, 11), (30, 10), (45, 9), (60, 6), (75, 2), (90, 0) ] closest_lat, hours table[0] for lat, h in table: if abs(lat - latitude) abs(closest_lat - latitude): closest_lat, hours lat, h return hours对比要点命名风格函数与变量使用snake_casedaylight_hoursJS 版为camelCasedaylightHours表结构Python 用(纬度, 小时)二元元组列表JS 用{ lat, hours }对象数组两者在语义上等价迭代解包Python 用for lat, h in table直接解包元组配合closest_lat, hours双变量保存最近纬度 对应小时与 JS 的entryclosest对象写法一一对应测试载体Python 版断言被包装在runPython中执行unittest的TestCase().assertEqualJS 版则直接调用assert.equal这是由两种challengeType28/29在评测器中的执行机制决定的。从 Markdown 到线上题库这道题背后的发布链路这道题不只是一道练习它的生命线贯穿整个仓库理解这条链路有助于你在本地复现与调试同系列题目题目编写题目本体就是上文所述的 Markdown 文件# --description--描述、# --hints--测试、# --seed--种子代码、# --solutions--参考解法四段式结构并登记进 curriculum/structure/blocks/daily-coding-challenges-javascript.json 的challengeOrder入库脚本tools/daily-challenges/seed-daily-challenges.ts 会先启动本地 Gatsby 客户端通过 GraphQL 查询superBlock: dev-playground、block: daily-coding-challenges-{javascript|python}两个 block 的全部挑战查询逻辑见 helpers.ts并校验 JS 与 Python 数量一致且等于 365随后把每个挑战按编号顺序写入 MongoDB 的DailyCodingChallenges集合从 2025-08-11 起每天推进一个日期START_DATE被硬编码并在脚本中做了日期不得随意变更的健全性校验接口下发API 侧提供每日挑战查询端点位于 api/src/daily-coding-challenge/routes并配有同名.test.ts客户端按日期请求前端渲染client/src/client-only-routes/show-daily-coding-challenge.tsx 收到接口返回后用validateDailyCodingChallengeSchema做结构校验再通过formatChallengeData把数据库结构转换为经典挑战ShowClassic组件可消费的 props——其中 JS 挑战被标记为challengeType: 28、helpCategory: JavaScriptPython 为challengeType: 29、helpCategory: Python测试与种子文件内容则从数据库中的javascript.tests/challengeFiles注入评测执行# --hints--里的断言最终以交互式测试形式在浏览器端对学习者提交的函数求值本文表格中的 8 个用例就是判定代码是否通过的唯一依据。因此如果你想在本地跑通这道题最快的路径是启动仓库客户端与本地 MongoDB执行 seed-daily-challenges.ts 完成入库后访问每日挑战页面如果想快速验证算法本身则可以直接在浏览器控制台或 Node REPL 中粘贴官方参考解法并逐一运行 8 个断言。延伸与总结这道题真正训练的能力Daylight Hours 表面是地理 数学应用题实则精准训练了三条可迁移的编程能力数据与逻辑分离对照表作为显式数据存在算法与数据解耦——后续若表项修正例如采用更精确的天文模型只需改表而不动扫描逻辑最近邻匹配的建模能力取最接近的档位在工程中极其常见如地图网格归属、离散分档计费、颜色量化、调度就近分配其本质都是对有序基准做距离度量与最优选择以测评为准的严谨性8 条断言分别覆盖精确命中、南北半球、极值边界与中点就近四种分支提醒你在实现近似查询类功能时必须考虑平局、边界与极端输入的语义。官方给出的双语言解法用一次线性扫描 绝对距离比较完成了所有约束在理解了严格小于保留先遇表项、整数输入不触发平局这一细节后你甚至可以进一步挑战自己能否改用二分查找把 O(n) 优化为 O(log n)能否把函数推广为接收任意纬度含小数并正确处理平局这些延伸正是每日编程挑战系列希望逐步培养的算法思维。输出文章【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表