freeCodeCamp 每日编程挑战解析:用 Python 实现 Binary to Decimal(二进制转十进制)
2026/9/10 1:24:00 网站建设 项目流程

freeCodeCamp 每日编程挑战解析:用 Python 实现 Binary to Decimal(二进制转十进制)

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

本篇技术指南围绕 freeCodeCamp 开源仓库中的 Python 每日编程挑战Challenge 52: Binary to Decimal(挑战原文)展开,完整讲解题目要求、进制转换原理、官方测试用例、官方参考解法,并结合仓库源码剖析其双语言(Python/JavaScript)同步机制、自动化验证流程以及每日挑战的数据库发布链路。读完本文,你既能独立完成该挑战并通过全部测试,也能理解这类挑战在 freeCodeCamp 课程体系中的完整生命周期。

一、挑战背景:什么是 Daily Coding Challenge

daily-coding-challenges-python是 freeCodeCamp 课程体系中的一个挑战块(block),位于dev-playground超级块(superblock)之下。该块以legacy-challenge-list布局呈现,当前标记为isUpcomingChange: true,并使用多文件编辑器(usesMultifileEditor: true),帮助分类为Python,具体配置见 daily-coding-challenges-python.json。

这个挑战块的特殊之处在于:仓库同时维护了功能完全对等的JavaScript 版本挑战块(daily-coding-challenges-javascript,配置见 daily-coding-challenges-javascript.json,helpCategory为 JavaScript)。Challenge 52 在两个语言块中各有一份题目文件,且共享同一个挑战 ID68b7cadffed0e75a517da673

语言文件路径challengeType
Python68b7cadffed0e75a517da673.md29
JavaScript68b7cadffed0e75a517da673.md28

在 daily-coding-challenges-python.json 的challengeOrder中,本挑战被登记为Challenge 52: Binary to Decimal,紧随其后的Challenge 53: Decimal to Binary(ID68b7cadffed0e75a517da675)与本挑战互为逆运算,构成一组非常经典的进制转换练习。

二、题目要求与进制转换原理

题目原文

Given a string representing a binary number, return its decimal equivalent as a number.

即:给定一个表示二进制数的字符串,返回其对应的十进制数值(number 类型)

转换原理

二进制数只使用01两个数字来表示任意数值。要将二进制转换为十进制,需要把每一位乘以2的幂次,然后求和:

  • 最右侧一位乘以2^0
  • 其左侧相邻一位乘以2^1
  • 依此类推,每一位的幂次从右向左递增

例如,二进制数101转换为十进制等于5

1 * 2^2 + 0 * 2^1 + 1 * 2^0 = 4 + 0 + 1 = 5

这一原理是理解整个挑战的核心:二进制是一种基数为 2 的位置计数法,每一位的"权重"是 2 的幂,而非十进制中的 10 的幂。

三、测试用例(Hints)逐条解析

挑战文件中的--hints--部分定义了 4 个测试断言,全部通过runPython包装的 Python 标准库unittest执行。注意 Python 版本的函数命名为snake_caseto_decimal(与 JavaScript 版的toDecimal命名风格保持一致)。

测试输入期望输出推导过程
to_decimal("101")51×2² + 0×2¹ + 1×2⁰ = 4 + 0 + 1
to_decimal("1010")101×2³ + 0×2² + 1×2¹ + 0×2⁰ = 8 + 0 + 2 + 0
to_decimal("10010")181×2⁴ + 0 + 0 + 1×2¹ + 0 = 16 + 2
to_decimal("1010101")8564 + 16 + 4 + 1 = 85

每个测试用例的实际断言代码如下(以第一个为例):

({test: () => { runPython(` from unittest import TestCase TestCase().assertEqual(to_decimal("101"), 5)`) }})

这里揭示了 freeCodeCamp 挑战的双层测试机制:外层用 JavaScript 的runPython内嵌 Python 代码片段,内层则调用 Pythonunittest.TestCase.assertEqual做严格相等断言。这意味着你的to_decimal函数必须返回 Python 的整数5,而不是字符串"5"

四、初始代码与官方参考解法

初始代码(Seed)

def to_decimal(binary): return binary

初始函数只是把输入原样返回("101"返回"101"字符串),显然无法通过任何测试。你需要在函数体内实现真正的转换逻辑。

官方参考解法

def to_decimal(binary): decimal = 0 for i, bit_char in enumerate(reversed(binary)): bit = int(bit_char) decimal += bit * (2 ** i) return decimal

逐行解读

  1. reversed(binary):反转字符串,使最右侧(最低位)的字符排在第一位,从而让枚举下标i直接对应 2 的幂次;
  2. enumerate(...):同时取出下标i与字符bit_char,其中i即该位应乘的幂次;
  3. int(bit_char):把单个字符'0''1'转换为整数01
  4. decimal += bit * (2 ** i):按位置权累加,等价于题目描述中的"每位乘以 2 的幂后求和";
  5. 函数返回整数decimal,与测试断言的类型要求一致。

复杂度分析:设二进制字符串长度为n,该解法只需一次线性遍历,时间复杂度为O(n),空间复杂度为O(1),属于该问题的最优量级。

五、JavaScript 版本的对照实现

为保证每日挑战对编程语言选择的包容性,仓库为同一挑战维护了 JS 版本。其初始代码与参考解法如下:

function toDecimal(binary) { let decimal = 0; for (let i = 0; i < binary.length; i++) { const bit = parseInt(binary[binary.length - 1 - i], 10); decimal += bit * Math.pow(2, i); } return decimal; }

与 Python 解法对照可发现同一算法的两种语言形态:

  • Python 用reversed(binary)+enumerate从左向右携带幂次信息;
  • JS 用下标换算binary.length - 1 - i从右向左取位,配合Math.pow(2, i)计算权重;
  • 两者都遵循"从右往左、位权递增"的核心算法骨架。

六、双语言一致性的自动化保障

你可能好奇:两个语言版本的挑战如何保证不"跑偏"?答案在测试文件 daily-challenges.test.js 中。该文件基于 Vitest 编写,核心校验逻辑包括:

  1. 数量匹配:JS 与 Python 两个块必须都存在且挑战数量大于 0;
  2. 数量相等:JS 与 Python 的每日挑战数量必须完全一致;
  3. 属性一致:按索引逐一配对,校验每个挑战的idtitledescription和测试数量(tests数组长度)是否完全一致,任何不匹配都会将错误信息汇总后触发断言失败。

这解释了为什么 Python 挑战的 ID68b7cadffed0e75a517da673与 JS 版本完全相同——这是仓库刻意设计的"一一对应"关系。

七、从挑战文件到每日推送:种子脚本链路

Daily Coding Challenge 并非静态页面,而是按"每天一道题"的节奏推送。理解这一机制可以帮你更好地定位本题在生产环境中的角色。核心脚本是 seed-daily-challenges.ts:

  1. dev-playground超级块通过 GraphQL 抓取全部挑战(客户端需开启 upcoming changes 才能暴露这些内容);
  2. 分别获取 JavaScript 与 Python 两个语言版本的挑战数组,并要求两者数量相等(此处期望365 道,对应全年每日一题);
  3. 调用 helpers.ts 中的combineChallenges,将同一天的 JS 与 Python 挑战合并为一条记录,并关联一个日期——起始日期硬编码为2025-08-11T00:00:00.000Z,每道题顺延一天(24 * 60 * 60 * 1000ms);
  4. 通过 MongoDB 的bulkWrite+replaceOne(upsert)写入DailyCodingChallenges集合,实现"已存在则替换、不存在则插入";
  5. 脚本内置起始日期校验与文档总数校验,防止意外改动影响已发布排期。

因此,Challenge 52 会被分配到一个具体日期,在前端(widget.tsx)的"今日挑战"入口中被渲染出来。从这个角度看,to_decimal不仅是一道练习题,更是 freeCodeCamp"每天一道编码挑战"产品形态中的一环。

八、延伸思考:配套的进制转换挑战

本题所在的块还围绕"进制与编码"安排了多个姊妹挑战,可一起练习形成体系:

  • Challenge 53: Decimal to Binary68b7cadffed0e75a517da675):与本题互为逆运算,将十进制转为二进制;
  • Challenge 62: Hex to Decimal68c497f3aaefc9fd9f1b0e26):十六进制转十进制,幂次变为 16;
  • Challenge 166: Hex Validator696655d24b614176d4c9b789):校验十六进制字符串合法性。

这些挑战共享同一套"按位乘幂累加"的思想,区别仅在于基数(base)不同。掌握to_decimal的写法后,你可以在本地用 Python 交互式环境验证任意输入:

# 本地手动验证 >>> to_decimal("101") 5 >>> to_decimal("1010101") 85 # 对照 Python 内置能力 >>> int("101", 2) 5

需要说明的是:int(binary, 2)是 Python 内置的快速转换方案,但本挑战的目的正是让你手写实现这一过程,以加深对位置计数法与位权的理解。若你希望验证更多边界输入,可自行扩展测试,例如"0"应返回0"11111111"应返回255——这些均不属于原文档的强制断言,但有助于巩固对算法的掌握。

九、小结

通过本文,你已完整掌握 freeCodeCamp Challenge 52 "Binary to Decimal" 的全部要素:

  • 算法本质:将二进制字符串按位乘以 2 的幂并累加,得到十进制整数;
  • 验收标准to_decimal需通过 4 个基于unittest的断言,覆盖 4 位到 7 位不等的二进制输入;
  • 参考实现reversed+enumerate+int的线性遍历解法,时间复杂度O(n)
  • 仓库机制:本挑战以相同 ID 存在于 Python(challengeType 29)与 JavaScript(challengeType 28)两个版本,通过 daily-challenges.test.js 保证双语言一致性,并最终由 seed-daily-challenges.ts 以每日一题的形式写入数据库推送给学习者。

现在,你可以在本地打开挑战文件,先尝试独立编写实现,再对照官方解法逐行验证自己的思路。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询