news 2026/9/10 8:20:22

freeCodeCamp 每日编程挑战解析:Jet Lagged 时差计算(Challenge 302,JavaScript 版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
freeCodeCamp 每日编程挑战解析:Jet Lagged 时差计算(Challenge 302,JavaScript 版)

freeCodeCamp 每日编程挑战解析:Jet Lagged 时差计算(Challenge 302,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 开源课程中每日编程挑战(Daily Coding Challenge)块的第 302 道题「Jet Lagged」展开:给定出发城市、到达城市、飞行时长与航行方向,编写getJetLagHours函数计算旅行者的时差小时数。文章完整复刻题目规格、公式与全部 7 个测试用例,逐行解读官方参考实现,并结合当前仓库中块配置、双语挑战文件、API 拉取路由与客户端校验器等源码,说明这道挑战在 freeCodeCamp 体系中从编写到运行的完整机制。读完你可以独立完成该题,并掌握其背后的"查表 + 线性公式 + 一位小数舍入"编程范式。

一、挑战背景:daily-coding-challenges-javascript 块

这道题属于 freeCodeCamp 课程结构中的daily-coding-challenges-javascript块,所有挑战文件集中存放在 curriculum/challenges/english/blocks/daily-coding-challenges-javascript 目录下,每题一个 Markdown 文件。块的元数据定义在 curriculum/structure/blocks/daily-coding-challenges-javascript.json 中,从该配置文件可以确认以下关键事实:

  • challengeOrder按顺序登记了从 Challenge 1: Vowel Balance 到 Challenge 365: The Last Challenge: Bucket Fill 3 共365 道每日挑战,本题目为其中的第 302 道;
  • usesMultifileEditor: true,即该块内的挑战在多文件编辑器中运行;
  • helpCategory: "JavaScript",帮助分类归入 JavaScript;
  • disableLoopProtectTests: true,禁用了防死循环保护测试,便于算法类解答自由编写循环;
  • isUpcomingChange: true,标识为新版课程体系中即将启用(upcoming)的内容;
  • blockLayout: "legacy-challenge-list",块内挑战以列表布局展示。

同时,daily-coding-challenges-javascriptdaily-coding-challenges-python两个块被登记进 curriculum/structure/superblocks/dev-playground.json 的块列表中,说明这套每日挑战以 JavaScript / Python 双语形式提供。本题目就存在两个语言版本:本文分析的 JavaScript 版(challengeType: 28)与 Python 版(challengeType: 29,见 curriculum/challenges/english/blocks/daily-coding-challenges-python/6a0dcd03ee4e68698080ef66.md)。

二、题目陈述与数据规格

题目原文要求:给定一个出发城市(departure city)、一个到达城市(arrival city)、飞行时长(小时)以及航行方向(travel direction),返回旅行者正在经历的时差小时数(jet lag hours)。函数签名为:

function getJetLagHours(departureCity, arrivalCity, flightDuration, direction) { return departureCity; }

四个参数的含义如下:

| 参数 | 类型 | 说明 | | - | - | - | |departureCity| string | 出发城市名,来自下表给出的 7 个城市 | |arrivalCity| string | 到达城市名,同样来自下表 | |flightDuration| number | 飞行时长,单位为小时 | |direction| string | 航行方向,取值为"east""west"|

题目给出的城市名单及其 UTC 偏移量(相对于 UTC 的小时数)是唯一的合法数据源,必须完整继承:

| City | Offset | | - | - | |"Los Angeles"| -8 | |"New York"| -5 | |"London"| 0 | |"Istanbul"| +3 | |"Dubai"| +4 | |"Hong Kong"| +8 | |"Tokyo"| +9 |

注意"London"的偏移为 0,即伦敦为 UTC 基准城市;"Los Angeles""New York"为负偏移(UTC 以西),其余城市为正偏移(UTC 以东)。

三、计算公式拆解

题目给出的时差计算分三步进行:

  1. 求两城时差:计算两个城市之间的时区差(小时),即arrivalCity的 UTC 偏移与departureCity的 UTC 偏移之差的绝对值;
  2. 确定方向乘子(direction multiplier):若航行方向为"east",乘子为1.5;否则(即"west")为1.0
  3. 套用公式求时差小时数
jetLagHours = timezoneDifference + (flightDuration * 0.1) * directionMultiplier

最终结果需四舍五入到一位小数后返回。

公式的业务含义可以这样理解:时差小时数由两部分构成——两城间的固定时区差(反映生物钟被"直接搬移"的跨度),以及飞行时长折算的疲劳加成(每 10 小时飞行折算 1 小时,向东飞行因昼夜节律提前而放大 1.5 倍,向西飞行保持 1.0 倍)。这道题的编程考点在于:城市到偏移量的查表映射、Math.abs求绝对差值、按方向条件选择乘子,以及最终的一位小数舍入。

四、测试用例全览与手算验证

原文档共给出 7 个测试用例,全部使用assert.equal做严格相等断言,测试的是四舍五入后精确到一位小数的数值。逐一列出并手算验证如下:

| # | 调用 | 期望结果 | 计算过程 | | - | - | - | - | | 1 |getJetLagHours("Istanbul", "Hong Kong", 10, "east")|6.5| diff = |8−3| = 5;5 + (10×0.1)×1.5 = 5 + 1.5 =6.5| | 2 |getJetLagHours("London", "New York", 8, "west")|5.8| diff = |−5−0| = 5;5 + (8×0.1)×1.0 = 5 + 0.8 =5.8| | 3 |getJetLagHours("Hong Kong", "Tokyo", 4, "east")|1.6| diff = |9−8| = 1;1 + (4×0.1)×1.5 = 1 + 0.6 =1.6| | 4 |getJetLagHours("Dubai", "London", 7, "west")|4.7| diff = |0−4| = 4;4 + (7×0.1)×1.0 = 4 + 0.7 =4.7| | 5 |getJetLagHours("Los Angeles", "Hong Kong", 15, "west")|17.5| diff = |8−(−8)| = 16;16 + (15×0.1)×1.0 = 16 + 1.5 =17.5| | 6 |getJetLagHours("Tokyo", "Dubai", 9, "west")|5.9| diff = |4−9| = 5;5 + (9×0.1)×1.0 = 5 + 0.9 =5.9| | 7 |getJetLagHours("New York", "Istanbul", 10, "east")|9.5| diff = |3−(−5)| = 8;8 + (10×0.1)×1.5 = 8 + 1.5 =9.5|

用例设计有意识地覆盖了各种情形:跨 UTC 线的城市对(Los Angeles → Hong Kong,时差达 16 小时)、包含 0 偏移的伦敦(London → New York)、同一半球的短程航线(Hong Kong → Tokyo,时差仅 1 小时)、负偏移出发城市(New York → Istanbul)以及"东/西"两种方向。任何实现若漏掉绝对值、乘子或舍入任一环节,都会被其中某个用例精确捕获。

五、JavaScript 官方参考实现逐行解读

原文档的--solutions--段给出了完整官方解答,这里是逐行展开的版本,附带每步说明:

function getJetLagHours(departureCity, arrivalCity, flightDuration, direction) { // 1. 城市名 -> UTC 偏移量的查表映射 const offsets = { "Los Angeles": -8, "New York": -5, "London": 0, "Istanbul": +3, "Dubai": +4, "Hong Kong": +8, "Tokyo": +9 }; // 2. 通过键查找出发/到达城市的偏移量 const depOffset = offsets[departureCity]; const arrOffset = offsets[arrivalCity]; // 3. 时区差取绝对值(保证结果非负) const timezoneDiff = Math.abs(arrOffset - depOffset); // 4. 方向乘子:east -> 1.5,其余(west)-> 1.0 const multiplier = direction === "east" ? 1.5 : 1.0; // 5. 套用公式 const score = timezoneDiff + (flightDuration * 0.1) * multiplier; // 6. 四舍五入到一位小数:先乘 10、round 后再除回 return Math.round(score * 10) / 10; }

几个实现细节值得展开:

  • 查表映射:用对象字面量offsets建立城市名到偏移量的 O(1) 查找表,比switch或一串if/else更简洁、更易扩展;
  • 绝对时差Math.abs(arrOffset - depOffset)消去了"从西到东"与"从东到西"的符号问题,因此函数对任意城市顺序都返回非负时差;
  • 三元表达式选乘子direction === "east" ? 1.5 : 1.0精确对应题目"if travelling east, it's 1.5, otherwise, it's 1.0"的表述,任何非"east"值(包括"west")都落入 1.0 分支;
  • 一位小数舍入Math.round(score * 10) / 10是 JavaScript 中"四舍五入到 n 位小数"的经典手写方式。注意Number.prototype.toFixed(1)返回的是字符串而非数字,且存在二进制浮点舍入行为差异(如(1.005).toFixed(2)的经典陷阱),因此assert.equal严格数值断言下使用Math.round(score * 10) / 10更可靠。

六、Python 版本对照:同一道题的另一种表达

同 ID 的 Python 版位于 curriculum/challenges/english/blocks/daily-coding-challenges-python/6a0dcd03ee4e68698080ef66.md,函数名为get_jet_lag_hours,核心算法完全一致,仅语法与测试写法不同:

def get_jet_lag_hours(departure_city, arrival_city, flight_duration, direction): offsets = { "Los Angeles": -8, "New York": -5, "London": 0, "Istanbul": 3, "Dubai": 4, "Hong Kong": 8, "Tokyo": 9 } timezone_diff = abs(offsets[arrival_city] - offsets[departure_city]) multiplier = 1.5 if direction == "east" else 1.0 score = timezone_diff + (flight_duration * 0.1) * multiplier return round(score, 1)

两版差异点归纳:

  • 命名规范:JS 用 camelCase(getJetLagHours),Python 用 snake_case(get_jet_lag_hours);
  • 舍入 API:Python 直接用内置round(score, 1)即可得到一位小数的浮点数,JS 则需Math.round(score * 10) / 10手工实现;
  • 测试注入方式:JS 版测试直接写assert.equal(getJetLagHours(...), 6.5);Python 版则通过runPython在浏览器中执行 Python 测试代码,借助标准库unittest.TestCase().assertEqual(...)完成断言,例如:
({test: () => { runPython(` from unittest import TestCase TestCase().assertEqual(get_jet_lag_hours("Istanbul", "Hong Kong", 10, "east"), 6.5)`) }})
  • 种子代码:JS 版种子为return departureCity;(占位返回),Python 版种子为return departure_city,均只要求学习者填充函数体。

七、从源码看这道挑战的完整运作机制

挑战文件本身只是课程内容的一部分,freeCodeCamp 通过一整套链路把6a0dcd03ee4e68698080ef66.md这类文件变成用户可在线解答、可自动判题的每日挑战。

1. 文件结构约定。每个挑战 Markdown 以 YAML frontmatter 开头,声明id(全局唯一)、titlechallengeType(28 对应 JavaScript 版每日挑战、29 对应 Python 版)与dashedName;正文通过# --description--(题目描述)、# --hints--(断言测试)、# --seed--/--seed-contents--(种子代码)与# --solutions--(官方解答)等分区标记组织,课程构建器据此解析并渲染。

2. 块与超级块配置。块的挑战顺序与编辑器配置定义在 curriculum/structure/blocks/daily-coding-challenges-javascript.json,两个双语块被收录进 curriculum/structure/superblocks/dev-playground.json。

3. API 按日期下发挑战。后端在 api/src/daily-coding-challenge/routes/daily-coding-challenge.ts 中注册了公开 GET 路由/daily-coding-challenge/date/:date:先解析YYYY-MM-DD格式日期(格式非法返回 400),再通过 Prisma 查询dailyCodingChallenges表,若日期晚于美国中部时区的今天(challenge.date > getUtcMidnight(getNowUsCentral()))或记录不存在则返回 404,命中则返回挑战完整数据,并同步向 Sentry 记录dcc.challenge_viewed等指标。文件注释还说明:该接口只用于获取挑战信息,挑战提交仍走主挑战完成路由。

4. 客户端数据校验。前端通过 client/src/utils/daily-coding-challenge-validator.ts 用 Joi 校验从数据库下发的挑战结构:要求顶层包含idchallengeNumber(≥1 的整数)、titledatedescription,且javascriptpython两个语言版本都必须携带非空的tests(含texttestString)与challengeFiles(含fileKeycontents)数组——这正是本挑战文件中--hints----seed-contents--经解析后在数据层的对应形态。

5. 前端展示组件。用户界面上,client/src/components/daily-coding-challenge 目录提供了日历(calendar.tsx)、小部件(widget.tsx)、未找到提示(not-found.tsx)等组件;其中 helpers.ts 基于date-fnsdate-fns-tz实现"今天"的判定——按America/Chicago时区格式化日期、校验yyyy-MM-ddMM-DD格式、并把 2 月 29 日映射到 2 月 28 日(toMonthDay),与后端"挑战日期截止于美国中部今天"的逻辑保持一致。

八、延伸思考与边界情况

官方实现已能通过全部测试,但值得留意的边界情况有:

  • 未知城市:若传入表中不存在的城市名,offsets[departureCity]返回undefinedarrOffset - depOffset会得到NaNassert.equal无法通过。题目保证输入合法,因此官方解答未做兜底;如需健壮实现,可先判断departureCity in offsets再计算。
  • 舍入方向Math.round遵循"四舍五入到最近的整数,.5 时向上"的规则(正数场景),与 Pythonround的"银行家舍入"行为略有差异,但本题所有用例的第三位小数都不触发差异点,两版结果一致。
  • 公式本身的非线性:飞行时长以 0.1 倍率线性折算进结果,意味着 15 小时飞行无论向东还是向西都贡献 1.5 或 1.5×1.5 小时的加成——理解这一点有助于你在类似"权重公式 + 阈值判定"的题目中快速建立模型。
  • 进一步练习:可以自行扩展城市表(例如增加 UTC+5:30 的德里、UTC+1 的巴黎)、支持"同名城市返回 0"、或把结果改为向上取整到半小时,以此加深对查表与舍入边界的理解。

参考资源

  • 挑战原文(JS 版):curriculum/challenges/english/blocks/daily-coding-challenges-javascript/6a0dcd03ee4e68698080ef66.md
  • 挑战原文(Python 版):curriculum/challenges/english/blocks/daily-coding-challenges-python/6a0dcd03ee4e68698080ef66.md
  • 块配置:curriculum/structure/blocks/daily-coding-challenges-javascript.json
  • 超级块配置:curriculum/structure/superblocks/dev-playground.json
  • 后端按日期拉取接口:api/src/daily-coding-challenge/routes/daily-coding-challenge.ts
  • 前端数据校验:client/src/utils/daily-coding-challenge-validator.ts
  • 前端日期/时区辅助:client/src/components/daily-coding-challenge/helpers.ts
  • 前端展示组件:client/src/components/daily-coding-challenge

【免费下载链接】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 8:18:27

Metabase 怎么作为 systemd 系统服务运行?

Metabase 怎么作为 systemd 系统服务运行? 【免费下载链接】metabase The easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart: 项目地址: https://gitcode.com/GitHub_Trending/me/metab…

作者头像 李华
网站建设 2026/9/10 8:18:12

五子棋AI教练:用神经网络教孩子建立大局观

/* 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 8:14:24

WorkBuddy办公提效验证方法:三指标实测AI Agent真实价值

1. 这不是又一个“AI提效”口号,而是一套能亲手验证WorkBuddy真实价值的实操方法你有没有试过刚装上WorkBuddy,兴奋地让它“自动整理会议纪要”“一键生成周报”,结果等了三分钟,它把老板的发言记成了隔壁工位小王点的外卖清单&am…

作者头像 李华
网站建设 2026/9/10 8:06:51

多模态与视觉大模型开发,OpenCV仍是必修课:实战学习路线全解

2026年了,聊多模态和视觉大模型开发,还有人觉得OpenCV是过时的“传统图像处理”,我每次听到都想把人拉过来坐下聊聊。恰恰是我最近几年做的多模态融合、视觉语言模型项目里,OpenCV几乎每天都在用,从图片清洗、图像预处…

作者头像 李华