freeCodeCamp Python 每日挑战第 40 题精讲:Photo Storage 的单位换算与整除运算
【免费下载链接】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 Challenges」Python 系列的第 40 道题展开:给定每张照片的大小(MB)与硬盘容量(GB),计算硬盘最多能存储多少张完整照片。文章不仅会逐条拆解官方给出的全部测试用例与解法,还会结合仓库中挑战的存储结构、API 路由与数据校验实现,帮助你理解这类「单位换算 + 向下取整」题目的完整解题链路与工程化背景。读完本文,你既能独立通过这道题,也能掌握 freeCodeCamp 每日挑战从题库到前端展示的运作方式。
一、题目背景:它在 Daily Coding Challenges 体系中的位置
这道题位于仓库的 Python 每日挑战块(block)中,文件路径为 curriculum/challenges/english/blocks/daily-coding-challenges-python/68b1f72371a5ac895ac70a02.md。根据 curriculum/structure/blocks/daily-coding-challenges-python.json 的定义,该块:
helpCategory为Python,即题目面向 Python 学习者;usesMultifileEditor为true,学员在多功能编辑器中作答;blockLayout为legacy-challenge-list,按挑战列表顺序编排;- 全块共 200+ 道 Python 小题,从「Vowel Balance」到「Letter and Number Count」,覆盖数值计算、字符串处理、数据结构与算法等主题。
本题Challenge 40: Photo Storage属于该块前 40 道中的一道数值计算题,与其相邻的第 41 题File Storage、第 42 题Video Storage组成了「存储容量换算」小主题,本题目的是让学习者熟练处理跨单位换算与整除取整。
二、题目描述与约束条件
题目原文要求如下:
给定照片大小(以兆字节 MB 为单位)和硬盘容量(以千兆字节 GB 为单位),返回该硬盘能够存储的照片数量,须满足以下约束:
- 1 GB 等于 1000 MB;
- 返回硬盘能够存储的完整照片数量。
据此,题目的函数签名与两个关键约束为:
def number_of_photos(photo_size_mb, drive_size_gb): # photo_size_mb:单张照片大小(MB,可为小数) # drive_size_gb:硬盘容量(GB,可为小数) ...两点约束值得注意:
- 采用十进制换算(1 GB = 1000 MB),而非二进制换算(1 GiB = 1024 MiB)。这是消费级存储设备厂商常用的标称方式,也是本题答案的关键前提——
number_of_photos(1, 1)的期望值 1000 直接由 1 GB = 1000 MB 推导而来。 - 只返回完整照片数,即对计算结果做向下取整(floor),丢弃不能存下完整一张照片的零头。这一约束决定了必须使用整数除法而不是普通除法。
三、官方测试用例逐条推演
挑战的--hints--部分给出了 5 组断言,全部通过 Python 内置unittest框架执行。我们逐条验证换算逻辑:
({test: () => { runPython(` from unittest import TestCase TestCase().assertEqual(number_of_photos(1, 1), 1000)`) }})| 输入(photo_size_mb, drive_size_gb) | 硬盘容量换算为 MB | 计算结果 | 期望输出 |
|---|---|---|---|
(1, 1) | 1 × 1000 = 1000 | 1000 ÷ 1 = 1000 | 1000 |
(2, 1) | 1 × 1000 = 1000 | 1000 ÷ 2 = 500 | 500 |
(4, 256) | 256 × 1000 = 256000 | 256000 ÷ 4 = 64000 | 64000 |
(3.5, 750) | 750 × 1000 = 750000 | 750000 ÷ 3.5 ≈ 214285.71 → 取整 | 214285 |
(3.5, 5.5) | 5.5 × 1000 = 5500 | 5500 ÷ 3.5 ≈ 1571.42 → 取整 | 1571 |
观察最后两组用例:照片大小与硬盘容量都是浮点数,除不尽的结果必须向下取整。例如750000 / 3.5 = 214285.714...,只能完整存储 214285 张,第 214286 张会因空间不足而无法容纳——这正是「返回完整照片数量」这一约束的体现。
四、从种子代码到解决方案
挑战为学员提供了种子代码,函数体只有一个占位返回值,等待被替换:
def number_of_photos(photo_size_mb, drive_size_gb): return photo_size_mb官方解决方案如下:
def number_of_photos(photo_size_mb, drive_size_gb): drive_size_mb = drive_size_gb * 1000 return drive_size_mb // photo_size_mb其推导思路可分为两步:
第 1 步:统一单位。用drive_size_gb * 1000把硬盘容量从 GB 换算为 MB,得到以 MB 为单位的可用总空间drive_size_mb。这一步骤直接落实了「1 GB 等于 1000 MB」的约束。
第 2 步:整除取整。用整数除法运算符//计算drive_size_mb // photo_size_mb,得到能存储的完整照片数。//会对商向下取整,天然满足「返回完整照片数量」的要求,无需再调用int()或math.floor()。
为什么用//而不是/或int()
| 写法 | (3.5, 750)的结果 | 是否符合要求 |
|---|---|---|
drive_size_mb / photo_size_mb | 214285.71428571428(浮点数) | 否,不是整数 |
int(drive_size_mb / photo_size_mb) | 214285 | 是,但多一步转换 |
drive_size_mb // photo_size_mb | 214285(直接整除) | 是,最简洁 |
对于正数而言,int(x / y)与x // y结果一致;但//语义更清晰、性能更优,且能直接处理浮点操作数(Python 的//支持浮点数向下取整),是本题最合适的运算符。
边界情况与可扩展讨论
- 照片大小大于硬盘容量:如
number_of_photos(2000, 1),换算后1000 // 2000 = 0,返回 0,逻辑正确。 - 照片大小等于硬盘容量:如
number_of_photos(1000, 1),1000 // 1000 = 1,恰好存一张。 - 小数照片大小:如
number_of_photos(0.5, 1),1000 // 0.5 = 2000,浮点数整除依然成立。 - 工程化改进:若未来约束改为二进制换算(1 GiB = 1024 MiB),只需将常量 1000 替换为 1024;若要求返回「还能剩多少 MB」,可补充取余运算
drive_size_mb % photo_size_mb。
五、在 freeCodeCamp 中挑战是如何被检验与运行的
这道题并非静态文本,而是 freeCodeCamp「Daily Coding Challenges」线上功能的一部分。其验证机制与工程链路可以从仓库源码中得到印证:
1. 测试以runPython方式注入
文档的--hints--使用runPython(...)在学员代码环境中执行unittest断言(见 challenge 文件)。每一条 hint 都是一次独立的TestCase().assertEqual(...)调用,5 组用例全部通过后挑战才算完成。
2. 数据库中的结构校验
每日挑战从题库数据库读出后,前端会用 Joi 对数据结构做严格校验。见 client/src/utils/daily-coding-challenge-validator.ts:每条挑战必须包含id、challengeNumber、title、date、description,以及javascript与python两种语言的tests(含text与testString)和challengeFiles。也就是说,本题在数据库中会同时保存 Python 的种子代码与测试字符串,供每日挑战组件读取渲染。
3. 后端 API 按日期提供挑战
挑战内容通过 API 对外提供,路由实现在 api/src/daily-coding-challenge/routes/daily-coding-challenge.ts,包括:
GET /daily-coding-challenge/today:返回今天的挑战;GET /daily-coding-challenge/date/:date:按YYYY-MM-DD返回指定日期的挑战(晚于最后挑战日期会返回 404);GET /daily-coding-challenge/day/:day:按MM-DD返回(自动映射到最近的源日期);GET /daily-coding-challenge/month/:month:按YYYY-MM返回当月挑战列表;GET /daily-coding-challenge/all与GET /daily-coding-challenge/newest:分别返回全部挑战与最新挑战日期。
值得注意的细节是:所有路由都以美国中部时间(US Central)为「今天」的判定基准,且不会返回日期晚于今天的挑战——这意味着 Photo Storage 这类题目只有在排期日期到达后才会对学习者开放。
4. 题库是如何种入数据库的
题库种子脚本位于 tools/daily-challenges/README.md:脚本通过 GraphQL 从启用了「upcoming changes」的客户端获取「Dev Playground」超级块中的挑战,写入 MongoDB 的DailyCodingChallenges集合。运行前需将 tools/daily-challenges/sample.env 复制为.env并配置MONGOHQ_URL,然后在tools/daily-challenges目录下执行:
pnpm seed-daily-challenges前端展示组件位于 client/src/components/daily-coding-challenge/,其中widget.tsx负责当日挑战的答题小部件,calendar.tsx提供按月历查看历史挑战的入口。至此,「题库 Markdown → 种子脚本 → MongoDB → API → 前端组件」的完整链路便闭环了。
六、小结与举一反三
本题Photo Storage的核心考点可以浓缩为一句话:先统一单位(GB → MB),再用整数除法取整。它同时训练了三项基本功:
- 单位换算意识:识别题目给定的换算率(1 GB = 1000 MB),切勿想当然地套用 1024;
- 整除语义:理解「完整数量」等价于向下取整,选择
//而非/; - 浮点输入处理:Python 的
//与*都能透明处理浮点数,使代码在整数与小数输入下均保持一致行为。
如果你已完成此题,不妨继续挑战同块的 第 41 题 File Storage 与 第 42 题 Video Storage,它们的核心思路与本题一脉相承:同样是「单位换算 + 容量分配」,但在数据维度上做了延伸,能帮助你巩固这类存储计算题的通用解法。
【免费下载链接】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),仅供参考