ARTICLE DETAIL

资讯详情

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

freeCodeCamp 每日编程挑战第一题:Vowel Balance 元音均衡问题详解与课程工程实现

freeCodeCamp 每日编程挑战第一题:Vowel Balance 元音均衡问题详解与课程工程实现 freeCodeCamp 每日编程挑战第一题Vowel Balance 元音均衡问题详解与课程工程实现【免费下载链接】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 1: Vowel Balance 为主体完整解析题目的约束定义、全部测试用例、参考解法的每一行实现逻辑并结合课程 schema、区块结构与种子脚本等仓库源码说明这道题在 freeCodeCamp 课程流水线中的完整落地方式。读完你可以独立复现该题的解题思路与边界处理并理解课程挑战文件从 Markdown 定义到前端运行的整条链路。一、题目定义判定字符串前后两半的元音数量是否相等该挑战文件位于 6814d8e1516e86b171929de4.md其 frontmatter 声明了三个关键元数据字段值含义id6814d8e1516e86b171929de4挑战在数据库与课程结构中的唯一标识ObjectId 格式challengeType28挑战类型对应dailyChallengeJsJavaScript 每日挑战dashedNamechallenge-1该题在区块内的连字符短名其中challengeType: 28的类型映射定义在 challenge-types.ts 中const dailyChallengeJs 28。同一个配置文件进一步决定了该题在前端如何呈现与提交viewTypes 将dailyChallengeJs映射为classic视图即使用经典的编辑器加测试面板布局submitTypes 将其映射为tests即通过运行内嵌测试来判定完成而不是提交外部项目链接getDailyCodingChallengeLanguage 将类型 28 的语言标记为javascript。题目描述原文完整继承给定一个字符串判断其前半部分的元音字母数量是否等于后半部分的元音字母数量。约束如下字符串可以包含任意字符a、e、i、o、u不区分大小写被视为元音若字符串长度为奇数忽略正中间的字符。题目给出的初始代码seed只返回入参本身需要开发者补全逻辑function isBalanced(s) { return s; }二、测试用例逐条验证文档中的 hints 部分给出了 7 组测试断言它们共同覆盖了偶数长度、奇数长度、含空格与符号、纯字母全表等场景。逐一推演如下按参考解法的切分规则half Math.floor(s.length / 2)输入长度前半段slice(0, half)中间字符后半段前半元音后半元音期望racecar7racccar1a1atrueLorem Ipsum11Lorem空格Ipsum2o,e2I,utrueKitty Ipsum11KittyIpsum1i2I,ufalsestring6str无ing01ifalse 100trueabcdefghijklmnopqrstuvwxyz26前 13 个字母无后 13 个字母3a,e,i2o,ufalse123A#b!E*456-o.U17123A#b!E456-o.U2A,E2o,Utrue这些断言的原始形式在文档中以assert.isTrue/assert.isFalse书写例如assert.isTrue(isBalanced(racecar)); assert.isFalse(isBalanced(Kitty Ipsum));从用例分布可以看出出题意图奇偶分支都要走到racecar奇数、有中间字符与string偶数、无中间字符分别验证两条切分路径大小写不敏感123A#b!E*456-o.U中前半段的大写A、E与后半段的小写o、大写U都必须被计入因此实现里必须做toLowerCase()非字母字符不参与计数数字、标点、空格只影响长度与切分位置本身不是元音退化为 0 对 0 也成立 前后两半都没有元音0 0应返回true。三、参考解法逐行解析文档中提供的标准解法solutions 部分如下核心是“定中线、切两半、数元音、比大小”四步function isBalanced(s) { const vowels aeiou; const half Math.floor(s.length / 2); let firstHalf s.slice(0, half); let secondHalf s.length % 2 0 ? s.slice(half) : s.slice(half 1); const countVowels str str .toLowerCase() .split() .filter(c vowels.includes(c)) .length; return countVowels(firstHalf) countVowels(secondHalf); }逐行说明const vowels aeiou把元音集合作为普通字符串使用借助String.prototype.includes做成员判定避免每次循环都构造数组或正则。const half Math.floor(s.length / 2)对长度取整除得到前段长度。偶数长度时它正好是两段的公共分界奇数长度时它是“前段长度”中线字符下标即为half。前段切分s.slice(0, half)slice返回新字符串且不越界长度不足时返回空串因此对空字符串也天然安全。后段切分是本题唯一的易错点偶数长度s.slice(half)从分界点直接取到结尾两段无缝衔接奇数长度s.slice(half 1)多跳过一位正好把中线字符排除在统计之外。若误写成slice(half)中线字符会被算进后半段racecar这类用例就会出错。countVowels工具函数toLowerCase()统一大小写 →split()拆成字符数组 →filter(c vowels.includes(c))只保留元音 →length得到计数。用链式调用把“计数”抽象成可复用的纯函数是这段解法结构清晰的关键。return countVowels(firstHalf) countVowels(secondHalf)只比较数量相等不关心具体是哪些元音因此函数返回的是布尔值而非原字符串——这与 seed 中return s;的行为形成对照也解释了为什么 7 组断言全部是isTrue/isFalse。边界情况与等价实现补充几个文档未展开、但实现时必须想清楚的边界空字符串half 0长度为偶数firstHalf 、secondHalf s.slice(0) 两边计数均为 0返回true。切分逻辑无需特判。元音计数可以用正则一行化(str.toLowerCase().match(/[aeiou]/g) || []).length其中|| []是为了处理match无匹配时返回null的情况。两种写法的时间复杂度同为 O(n)。单趟扫描写法也可以不真正切字符串而是遍历一次i half时匹配元音加 1、i s.length - half时加 -1奇数长度时中间位置i half不加不减最后判断累加值是否为 0。切分写法文档方案可读性更好单趟写法在超长字符串上少构造两个子串两者均可通过全部测试。四、这道题在课程工程中的位置理解题目本身之外仓库源码展示了它如何进入 freeCodeCamp 的教学流水线这部分内容可帮助维护者或贡献者定位相关代码。4.1 区块结构JavaScript 每日挑战是一个独立 Blockblock 配置文件 声明了该区块的关键属性{ isUpcomingChange: true, dashedName: daily-coding-challenges-javascript, usesMultifileEditor: true, helpCategory: JavaScript, disableLoopProtectTests: true, blockLayout: legacy-challenge-list, challengeOrder: [ { id: 6814d8e1516e86b171929de4, title: Challenge 1: Vowel Balance }, { id: 681cb05adab50c87ddb2e513, title: Challenge 2: Base Check } ] }其中challengeOrder的第一项就是本文主角可见该文件正是 “Challenge 1” 在区块中的排序依据。另外几个字段值得注意usesMultifileEditor: true表示该区块的编辑器支持多文件disableLoopProtectTests: true表示对该区块关闭了死循环保护测试从源码结构看这与每日挑战允许较长计算逻辑有关helpCategory: JavaScript决定求助按钮归类到 JavaScript 类目。同目录下还存在 Python 版姊妹区块 daily-coding-challenges-python.json对应challengeType: 29dailyChallengePy说明每日挑战是 JS 与 Python 双语言配对的。4.2 数据入库种子脚本按天生成 365 题seed-daily-challenges.ts 是把这些 Markdown 挑战灌入数据库的脚本从源码可以确认几个工程细节脚本从 GraphQL 拉取 JavaScript 与 Python 两侧的挑战数据并强制要求两侧数量一致否则直接抛错见 第 53-57 行常量EXPECTED_CHALLENGE_COUNT 365表明每年每日挑战的数量预期是一整年起始日期被硬编码为2025-08-11T00:00:00.000Z且脚本内有字符串比对的保护逻辑防止发布日期之后误改起始日期见 第 18-36 行每条挑战记录按challengeNumber i 1、date 起始日 i 天计算最终批量 upsert 到 MongoDB 的DailyCodingChallenges集合。也就是说本文的 “Challenge 1: Vowel Balance” 在数据库中就对应第 1 题、日期为 2025-08-11 的那条记录。4.3 运行时校验前端读取时的 Schema 守卫当日挑战从数据库读出后前端会用 Joi schema 做一次结构校验实现见 daily-coding-challenge-validator.ts。challengeDataFromDbSchema要求每条记录必须包含整数且不小于 1 的challengeNumber、必填的title/date/description以及javascript与python两个语言子对象——每个子对象又要求tests含text与testStringtestString即上文 hints 中那些assert.*断言的字符串形态和challengeFiles含fileKey与contents对应本文 seed 代码。这条链路解释了文档中# --hints--、# --seed--、# --solutions--三个区块在运行时各自的角色hints 变成可执行测试seed 成为编辑器初始内容solutions 供解题器solution viewer展示。4.4 服务端路由API 侧的读取入口位于 api/src/daily-coding-challenge/routes/daily-coding-challenge.ts配套的请求/响应 schema 在 api/src/daily-coding-challenge/schemas/daily-coding-challenge.ts模块说明见 api/src/daily-coding-challenge/README.md。五、小结Challenge 1: Vowel Balance 是一道围绕字符串切分与字符计数的入门题其全部技术要点可以浓缩为三点奇偶长度的切分差异slice(half)与slice(half 1)、大小写归一化后再做元音判定、以及 0 对 0 的空半段边界。仓库侧则展示了 freeCodeCamp 的课程工程能力一份 90 行的 Markdown描述 断言 种子 解法经由区块 JSON 排序、种子脚本按天落库、前端 Joi 校验与 classic 视图渲染最终成为网站上可运行、可判题的每日挑战。若要继续练习可直接在同目录 daily-coding-challenges-javascript 下查看后续的 Challenge 2: Base Check681cb05adab50c87ddb2e513等题目文件它们的结构与本文完全一致。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表