解析:用 Python 實(shí)現(xiàn) Longest Word(最長(zhǎng)單詞查找))
freeCodeCamp 每日編程挑戰(zhàn)解析用 Python 實(shí)現(xiàn) Longest Word最長(zhǎng)單詞查找【免費(fèi)下載鏈接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCampfreeCodeCamp 開(kāi)源倉(cāng)庫(kù)中內(nèi)置了一套「每日編程挑戰(zhàn)Daily Coding Challenge」體系其中 Challenge 50: Longest Word 是一道典型的 Python 字符串處理題目給定一個(gè)句子返回其中長(zhǎng)度最長(zhǎng)的單詞忽略句點(diǎn).對(duì)標(biāo)點(diǎn)遇到長(zhǎng)度并列時(shí)返回最先出現(xiàn)的那個(gè)。本文將以此題為骨架完整還原題目要求、三個(gè)判定用例、種子代碼與官方參考答案并深入到 freeCodeCamp 倉(cāng)庫(kù)的源碼與配置中說(shuō)明這類(lèi)題目在課程體系中的定位、測(cè)試執(zhí)行機(jī)制與前端運(yùn)行環(huán)境幫助你既會(huì)做題、也看懂背后的工程實(shí)現(xiàn)。題目全景Challenge 50: Longest Word本題對(duì)應(yīng)的挑戰(zhàn)文件位于 curriculum/challenges/english/blocks/daily-coding-challenges-python/68b7cadffed0e75a517da66f.md文件頭部的元數(shù)據(jù)清晰地定義了這道題的身份字段值說(shuō)明id68b7cadffed0e75a517da66f挑戰(zhàn)的唯一 ID全倉(cāng)庫(kù)全局唯一titleChallenge 50: Longest Word題目名稱(chēng)challengeType29挑戰(zhàn)類(lèi)型編號(hào)對(duì)應(yīng) Python 每日挑戰(zhàn)dashedNamechallenge-50URL 友好的短名稱(chēng)其中challengeType: 29是關(guān)鍵在 packages/shared/src/config/challenge-types.ts 中29被定義為dailyChallengePy即「Python 每日編程挑戰(zhàn)」專(zhuān)屬類(lèi)型。同一個(gè) blockdaily-coding-challenges-python中 200 道題目共用此類(lèi)型配套的 JavaScript 版本則使用28dailyChallengeJs。從源碼結(jié)構(gòu)可以推斷這類(lèi)題目在課程樹(shù)中統(tǒng)一歸入「Daily Coding Challenge」入口由 curriculum/structure/blocks/daily-coding-challenges-python.json 按challengeOrder數(shù)組維護(hù)順序——本挑戰(zhàn)id68b7cadffed0e75a517da66f正是列表中的第 50 項(xiàng)。需求拆解兩個(gè)邊界規(guī)則題目本身只給出兩句話(huà)的要求但濃縮了兩個(gè)極易被忽略的邊界規(guī)則Given a sentence, return the longest word in the sentence.—— 核心目標(biāo)返回句子中最長(zhǎng)的單詞。Ignore periods (.) when determining word length.—— 計(jì)算長(zhǎng)度時(shí)忽略句點(diǎn).也就是說(shuō)句子末尾的句號(hào)不能算作單詞長(zhǎng)度的一部分。If multiple words are ties for the longest, return the first one that occurs.—— 出現(xiàn)多個(gè)同樣長(zhǎng)度的單詞時(shí)必須返回最先出現(xiàn)的那一個(gè)即“第一勝出”規(guī)則而不是“最后一個(gè)勝出”。第二、三條規(guī)則直接決定了參考答案的寫(xiě)法官方解法中先用sentence.split()按空白拆詞這樣educational.會(huì)被拆成帶句點(diǎn)的educational.再用str.replace(., )去掉句點(diǎn)后比較長(zhǎng)度并且比較時(shí)使用嚴(yán)格大于而非大于等于從而保證并列時(shí)保留更早出現(xiàn)的單詞。判定用例Hints逐條解讀倉(cāng)庫(kù)文件中的--hints--部分是題目的自動(dòng)化測(cè)試全部通過(guò)runPython在瀏覽器端執(zhí)行 Python 代碼并用 Python 標(biāo)準(zhǔn)庫(kù)unittest的TestCase().assertEqual做斷言。三個(gè)用例完整如下用例一get_longest_word(coding is fun)應(yīng)返回coding。({test: () { runPython( from unittest import TestCase TestCase().assertEqual(get_longest_word(coding is fun), coding)) }})三個(gè)單詞coding6 字符、is2 字符、fun3 字符中coding最長(zhǎng)且唯一返回coding。用例二get_longest_word(Coding challenges are fun and educational.)應(yīng)返回educational。({test: () { runPython( from unittest import TestCase TestCase().assertEqual(get_longest_word(Coding challenges are fun and educational.), educational)) }})這是最核心的用例educational.字面上是 12 個(gè)字符但按規(guī)則忽略句點(diǎn)后是 11 個(gè)字符若實(shí)現(xiàn)時(shí)直接用原始字符串比長(zhǎng)度會(huì)把句點(diǎn)計(jì)入導(dǎo)致返回educational.或比較出錯(cuò)。官方實(shí)現(xiàn)先replace(., )再比長(zhǎng)度恰好保證返回去掉句點(diǎn)的educational。用例三get_longest_word(This sentence has multiple long words.)應(yīng)返回sentence。({test: () { runPython( from unittest import TestCase TestCase().assertEqual(get_longest_word(This sentence has multiple long words.), sentence)) }})此用例同時(shí)考驗(yàn)“忽略句點(diǎn)”和“并列取先”兩條規(guī)則multiple與sentence均為 8 字符但sentence在句子中出現(xiàn)得更早因此正確答案是sentence而不是multiple。若比較邏輯使用則會(huì)錯(cuò)誤地返回multiple。種子代碼與解題起點(diǎn)題目在--seed-contents--中給定了函數(shù)骨架學(xué)習(xí)者只需填充函數(shù)體def get_longest_word(sentence): return sentence可以看出默認(rèn)實(shí)現(xiàn)是直接原樣返回輸入的sentence字符串這顯然無(wú)法通過(guò)任何用例——這正是挑戰(zhàn)的起點(diǎn)學(xué)習(xí)者需要自己完成「拆詞 → 清洗標(biāo)點(diǎn) → 遍歷比較 → 返回最長(zhǎng)項(xiàng)」的完整邏輯。官方參考答案逐行剖析--solutions--段提供了官方的完整解法def get_longest_word(sentence): words sentence.split() longest for word in words: clean_word word.replace(., ) if len(clean_word) len(longest): longest clean_word return longest逐行拆解其設(shè)計(jì)意圖行代碼作用與要點(diǎn)1words sentence.split()默認(rèn)按任意空白字符空格、制表符、換行切分句子為單詞列表句點(diǎn)仍附著在最后一個(gè)單詞上2longest 初始化最長(zhǎng)單詞為空字符串保證任何非空單詞的長(zhǎng)度≥1都能覆蓋它3for word in words:順序遍歷天然保證“先出現(xiàn)的單詞優(yōu)先被記錄”4clean_word word.replace(., )去除該單詞中的所有句點(diǎn)實(shí)現(xiàn)“忽略句點(diǎn)”規(guī)則5if len(clean_word) len(longest):嚴(yán)格大于才更新并列時(shí)保留先出現(xiàn)的單詞6longest clean_word注意這里保存的是清洗后的單詞不帶句點(diǎn)與用例二期望的輸出一致7return longest返回結(jié)果該解法的時(shí)間復(fù)雜度為 O(n·m)n 為單詞數(shù)m 為平均單詞長(zhǎng)度空間復(fù)雜度 O(n)。replace(., )會(huì)移除單詞內(nèi)所有句點(diǎn)如縮寫(xiě)e.g.會(huì)被處理成eg在本題目給定用例下不影響正確性。變體與擴(kuò)展從官方解到通用解官方解法足夠簡(jiǎn)潔但了解變體有助于真正吃透“并列取先”與“忽略標(biāo)點(diǎn)”這兩個(gè)核心規(guī)則寫(xiě)法一key參數(shù) max等長(zhǎng)取先需謹(jǐn)慎def get_longest_word(sentence): words [w.replace(., ) for w in sentence.split()] return max(words, keylen)max在遇到相同key值時(shí)返回列表中最先出現(xiàn)的項(xiàng)因此天然滿(mǎn)足“并列取先”規(guī)則。但注意若用keylambda w: len(w)且在比較前未清洗句點(diǎn)則會(huì)在用例二上失敗。寫(xiě)法二顯式清洗 線(xiàn)性?huà)呙枵Z(yǔ)義最清晰def get_longest_word(sentence): longest for word in sentence.split(): clean word.strip(.,!?;:) if len(clean) len(longest): longest clean return longest把strip(.,!?;:)視作對(duì)“忽略句點(diǎn)”規(guī)則的泛化——題目只要求忽略.但把規(guī)則擴(kuò)展到常見(jiàn)句末標(biāo)點(diǎn)也不需要改動(dòng)循環(huán)結(jié)構(gòu)這體現(xiàn)了該題解法的可擴(kuò)展性。關(guān)于并列取先的深層原因if len(clean_word) len(longest)使用嚴(yán)格大于意味著后一個(gè)同長(zhǎng)度單詞永遠(yuǎn)不會(huì)覆蓋前一個(gè)這正是「return the first one that occurs」的代碼級(jí)體現(xiàn)。這也是本類(lèi)題最常被忽視的考點(diǎn)。工程視角這類(lèi)題目在 freeCodeCamp 中如何運(yùn)轉(zhuǎn)理解了題目本身后值得回到倉(cāng)庫(kù)源碼看看challengeType: 29是如何被整個(gè)體系識(shí)別和驅(qū)動(dòng)的。挑戰(zhàn)類(lèi)型的注冊(cè)與分發(fā)packages/shared/src/config/challenge-types.ts 是類(lèi)型的“總注冊(cè)表”const dailyChallengePy 29;第 31 行定義了類(lèi)型編號(hào)viewTypes中將dailyChallengePy映射為classic視圖第 135 行意味著本題與經(jīng)典代碼挑戰(zhàn)共用同一套編輯器界面submitTypes中映射為tests第 176 行即提交后通過(guò)運(yùn)行測(cè)試來(lái)判定對(duì)錯(cuò)getIsDailyCodingChallenge(challengeType)第 187 行通過(guò)dailyCodingChallengeTypes列表識(shí)別「每日挑戰(zhàn)」類(lèi)型含 JS 與 Python 兩種getDailyCodingChallengeLanguage(challengeType)第 204 行將dailyChallengePy映射為python用于確定運(yùn)行語(yǔ)言。因此當(dāng)學(xué)習(xí)者在前端進(jìn)入本題時(shí)系統(tǒng)會(huì)走「classic 編輯器 Python 語(yǔ)言 tests 提交」這一組合管線(xiàn)。測(cè)試如何被執(zhí)行為 Python 斷言本題的--hints--使用了runPython(...)包裹的unittest斷言這在 e2e 測(cè)試中有直接對(duì)應(yīng)物e2e/daily-coding-challenge.spec.ts 中構(gòu)造的 mock 挑戰(zhàn)數(shù)據(jù)python.tests[0].testString就是一個(gè)({test: () { runPython(\assert True True)}})形式第 41 行說(shuō)明該格式是每日挑戰(zhàn) Python 測(cè)試的標(biāo)準(zhǔn)載體。從倉(cāng)庫(kù)結(jié)構(gòu)可以推斷這類(lèi)測(cè)試在前端通過(guò)內(nèi)置的 Python 運(yùn)行時(shí)瀏覽器內(nèi)執(zhí)行運(yùn)行與項(xiàng)目自帶的 Python 課程如pythonProject、pyLab 等類(lèi)型共用同一套執(zhí)行機(jī)制。每日挑戰(zhàn)的入口與路由在課程地圖與落地頁(yè)上每日挑戰(zhàn)有獨(dú)立的入口組件client/src/components/daily-coding-challenge/widget.tsx 渲染「今天的挑戰(zhàn)」與「歷史歸檔」兩個(gè)按鈕分別指向/learn/daily-coding-challenge/${getMonthDayUsCentral()}與/learn/daily-coding-challenge/archive。日期計(jì)算依賴(lài) client/src/components/daily-coding-challenge/helpers.ts 中的getTodayUsCentral()——基于美國(guó)中部時(shí)區(qū)America/Chicago計(jì)算“今天”并對(duì) 2 月 29 日做特殊映射toMonthDay將02-29轉(zhuǎn)為02-28確保每年的同一天都對(duì)應(yīng)同一道題。Challenge 50 這類(lèi)題即通過(guò)「按月-日歸檔」的方式被收錄進(jìn)每日挑戰(zhàn)體系。在課程樹(shù)中的定位curriculum/structure/blocks/daily-coding-challenges-python.json 以challengeOrder數(shù)組維護(hù)了全部 Python 每日挑戰(zhàn)的順序本挑戰(zhàn)id68b7cadffed0e75a517da66f排在第 50 位前后分別是Challenge 49: CSV Header Parser與Challenge 51: Phone Number Formatter。文件頭還聲明了usesMultifileEditor: true與helpCategory: Python前者表示題目支持多文件編輯器本題雖只有一個(gè)函數(shù)但環(huán)境按多文件模式加載后者將題目歸入 Python 幫助分類(lèi)用于學(xué)習(xí)社區(qū)的問(wèn)題歸類(lèi)。本地體驗(yàn)如何運(yùn)行與驗(yàn)證倉(cāng)庫(kù)采用 pnpm workspace 管理見(jiàn)根目錄 package.json 與 pnpm-workspace.yaml。如果你想在本地復(fù)現(xiàn)本題或親手驗(yàn)證解法可以按以下方式操作僅驗(yàn)證算法邏輯直接把官方解法粘貼到任意 Python 3 環(huán)境運(yùn)行三個(gè)用例等價(jià)于from unittest import TestCase def get_longest_word(sentence): words sentence.split() longest for word in words: clean_word word.replace(., ) if len(clean_word) len(longest): longest clean_word return longest tc TestCase() tc.assertEqual(get_longest_word(coding is fun), coding) tc.assertEqual(get_longest_word(Coding challenges are fun and educational.), educational) tc.assertEqual(get_longest_word(This sentence has multiple long words.), sentence) print(All assertions passed)完整運(yùn)行 freeCodeCamp 前端與課程環(huán)境參考倉(cāng)庫(kù)根目錄 README.md 的指引安裝依賴(lài)并啟動(dòng)開(kāi)發(fā)服務(wù)器即可在瀏覽器中進(jìn)入每日挑戰(zhàn)頁(yè)面實(shí)際編寫(xiě)并提交代碼題目的判定邏輯由上文提到的 hints 測(cè)試驅(qū)動(dòng)無(wú)需額外配置。小結(jié)Challenge 50: Longest Word 雖是一道入門(mén)級(jí)字符串題但它完整覆蓋了「切分 → 清洗 → 比較 → 保持首次出現(xiàn)」四個(gè)典型處理步驟其官方實(shí)現(xiàn)更是將「忽略句點(diǎn)」與「并列取先」兩條邊界規(guī)則體現(xiàn)得淋漓盡致。通過(guò)閱讀其挑戰(zhàn)元數(shù)據(jù)challengeType: 29、共享配置challenge-types.ts、組件入口widget.tsx與 e2e 用例daily-coding-challenge.spec.ts你不僅能獨(dú)立 AC 這道題還能理解 freeCodeCamp 每日編程挑戰(zhàn)從題目文件到前端運(yùn)行、再到自動(dòng)化斷言的完整工程鏈路為繼續(xù)研究該開(kāi)源項(xiàng)目的課程體系打下基礎(chǔ)。【免費(fèi)下載鏈接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考