)
每年到算法準(zhǔn)備的高峰期總有人拿同一句話來問我LeetCode刷了三百道為什么一面試還是掛我翻過不少人的提交記錄基本都是兩種典型情況——要么在冷門難題里死磕到懷疑人生要么把LeetCode熱門100題刷了好幾遍卻只會對著原題默寫答案換個說法立刻卡殼。說實話對于絕大多數(shù)正在準(zhǔn)備求職、想系統(tǒng)提升算法題感的人來說熱門100題這份題單是性價比遠高于盲目刷題的訓(xùn)練材料。這篇總結(jié)是我自己刷完三遍、又拿它給幾批新人做帶練之后沉淀下來的版本會持續(xù)更新想把題型規(guī)律、高頻套路、易錯點和面試表達一次講透。如果你正在準(zhǔn)備算法面試或者處于刷題很久但沒有體系的階段這篇總結(jié)就是給你看的。我會先講清楚這份題單的定位和分布再按數(shù)據(jù)結(jié)構(gòu)和算法范式兩條主線拆套路最后把最容易翻車的細節(jié)和我自己的刷題節(jié)奏分享出來。這里沒有三天精通算法的捷徑但每一章都是可以直接拿去用的方法。1. 為什么是熱題100這份題單的真實定位1.1 它覆蓋的是主城任務(wù)不是全圖探索很多人對熱門100題有一個誤解覺得它是簡單題合集刷完也就是圖個心理安慰。實際完全不是。熱題100的題目來源是新題和經(jīng)典高頻題的交集基本就是算法面試的抽樣調(diào)查。你去翻各大公司的面經(jīng)會發(fā)現(xiàn)考題范圍高度集中數(shù)組與哈希、鏈表、二叉樹、動態(tài)規(guī)劃、雙指針輪來輪去就是這些主干知識點。熱門100題最大的價值是把算法面試最??嫉?主城任務(wù) 挑了出來讓你不用在全圖探索里浪費時間。打個比方如果把算法知識比作一座城市熱門100題是城市里的主干道和地標(biāo)建筑覆蓋的是你到任何一家公司面試都必須經(jīng)過的主路而那些競賽壓軸題、偏門冷題是城市周邊的野山路風(fēng)景可能很好但面試時大概率用不上。我見過不少人花大量時間死磕偏難怪題結(jié)果連二叉樹的層序遍歷都寫不利索這就是主次顛倒的典型。1.2 題型分布圖譜100題到底在考什么我自己在二刷的時候給熱題100做了一次細致的題型歸類。數(shù)據(jù)不會騙人下面是大概的分布情況題型類別大致占比代表題目數(shù)組與哈希25%兩數(shù)之和、三數(shù)之和、字母異位詞分組、和為 K 的子數(shù)組樹與圖20%二叉樹中序遍歷、驗證二叉搜索樹、島嶼數(shù)量、課程表動態(tài)規(guī)劃15%爬樓梯、打家劫舍、零錢兌換、最長遞增子序列鏈表10%反轉(zhuǎn)鏈表、環(huán)形鏈表 II、LRU 緩存、排序鏈表滑動窗口 / 雙指針10%盛最多水的容器、無重復(fù)字符的最長子串、最小覆蓋子串棧 / 隊列 / 堆10%每日溫度、滑動窗口最大值、前 K 個高頻元素回溯 / 貪心 / 其他10%全排列、組合總和、跳躍游戲、合并區(qū)間這張表的啟發(fā)很直接數(shù)組哈希、樹圖、動態(tài)規(guī)劃加在一起占了六成刷題的資源就應(yīng)該往這三塊傾斜。鏈表和雙指針看著占比不高但它們是高頻前置技能很多中等題和困難題都要用。如果時間緊張棧、隊列、堆可以先掌握模板題回溯和貪心在掌握基礎(chǔ)框架后再深入。另外熱題100里困難題的比例其實是偏高的大概有三分之一左右。所以刷這份題單時心態(tài)要調(diào)整好不需要每道題都獨立做出來能把題解徹底吃透、做到舉一反三就已經(jīng)達到目的。2. 數(shù)據(jù)結(jié)構(gòu)部分的高頻套路濃縮2.1 鏈表題三個固定動作解決八成問題鏈表題在熱題100里數(shù)量不算最多但每道都是面試官的心頭好。原因很簡單——鏈表題寫代碼不難難的是把指針關(guān)系理清楚而這恰恰最能看出一個人寫代碼時有沒有章法。我總結(jié)下來大多數(shù)鏈表題都能用三個固定動作拆解虛節(jié)點dummy、快慢指針、畫圖走一遍。第一個動作虛節(jié)點。只要涉及頭節(jié)點可能被刪除或修改的題先加一個 dummy 節(jié)點返回時再看 dummy.next。刪除鏈表的倒數(shù)第 N 個結(jié)點、反轉(zhuǎn)鏈表 II 這類題用虛節(jié)點能省掉大量的邊界判斷代碼可讀性也高一個檔次。第二個動作快慢指針。環(huán)形鏈表和環(huán)形鏈表 II 是快慢指針的經(jīng)典應(yīng)用。判斷成環(huán)很簡單快指針每次兩步、慢指針每次一步兩者相遇說明有環(huán)。找環(huán)入口需要一點數(shù)學(xué)推導(dǎo)其實也容易記住相遇后讓其中一個指針從頭節(jié)點重新出發(fā)另一個留在相遇點兩邊每次都走一步再次相遇的位置就是環(huán)入口。這個結(jié)論我在面過幾次之后發(fā)現(xiàn)自己根本記不牢于是專門推導(dǎo)了一遍后來再也沒忘——鏈表題里很多公式自己推一遍比背十遍都管用。第三個動作畫圖走一遍。有時候兩個指針互相倒來倒去光在腦子里想很容易亂。我在寫反轉(zhuǎn)鏈表這類題時一定會在本子上先把三個節(jié)點畫出來標(biāo)好每一步之后每個指針指向哪里再落筆寫代碼。這個方法聽起來很基礎(chǔ)但真的能避免寫完了一跑就死循環(huán)的尷尬?;匚逆湵?34是個很好的綜合題先用快慢指針找中點再把后半段反轉(zhuǎn)之后從頭逐一比較。三步都是上面說的固定動作但組合在一起就能考出你對鏈表操作的整體掌控力。熱題100里的排序鏈表148也一樣核心是先找中點再歸并找中點用的還是快慢指針。2.2 二叉樹題遞歸三要素是唯一正解二叉樹的題目在熱題100里少說也有十幾道解法基本都能歸到遞歸三要素確定遞歸函數(shù)的參數(shù)和返回值、確定終止條件、確定單層遞歸的邏輯。這三要素不是面試八股而是你寫任何遞歸都要過的三道關(guān)。拿熱題100里最簡單的二叉樹最大深度104來說遞歸函數(shù)返回當(dāng)前節(jié)點的高度終止條件是節(jié)點為空時返回 0單層邏輯是取左右子樹最大高度加一。三步理清楚代碼自然就出來了。這個框架再延伸一下——驗證二叉搜索樹98的中序解法、二叉樹的直徑543的后序解法、把二叉搜索樹轉(zhuǎn)換為累加樹538的反向中序解法都是同一套邏輯在不同遍歷順序下的應(yīng)用。真正讓我覺得通了的題是二叉樹中的最大路徑和124。它的核心思路是后續(xù)遍歷每次遞歸返回經(jīng)過當(dāng)前節(jié)點能貢獻給父路徑的最大單邊值同時在每個節(jié)點處更新一個全局最大值把左子樹貢獻、右子樹貢獻和當(dāng)前節(jié)點連起來的完整路徑算一遍。這種子樹返回一個值節(jié)點自己更新全局答案的模式是二叉樹難題的經(jīng)典套路。理解了它熱題100里很多樹形結(jié)構(gòu)題都能順下來。還有一個不得不提的是層序遍歷102。它雖然是廣度優(yōu)先的思路但實現(xiàn)起來有個小細節(jié)需要注意處理每一層時先記錄當(dāng)前隊列的長度再循環(huán)這么多個節(jié)點。如果不記錄長度直接把 level 循環(huán)寫成 while queue 非空那隊列里加入下一層節(jié)點后當(dāng)前層就會混在一起。這個細節(jié)我在帶練時見人踩了無數(shù)次屬于看著簡單但一跑就錯的典型。2.3 棧、隊列與單調(diào)棧從記住結(jié)構(gòu)到形成條件反射熱題100里的棧和隊列題不算多但每一道都值得單獨練習(xí)。有效的括號20是棧的入門題注意一個小陷阱如果是 ({[]}) 這種嵌套括號匹配順序是后進先出所以遇到右括號時彈出棧頂判斷即可最后還要檢查棧是不是空的。這道題我見過不少人忘了最后一步結(jié)果遇到 ([)] 這類輸入就漏判。真正有區(qū)分度的是單調(diào)棧。每日溫度739是理解單調(diào)棧最好的入口維護一個從棧底到棧頂遞減的下標(biāo)棧遍歷數(shù)組時只要當(dāng)前溫度大于棧頂下標(biāo)對應(yīng)的溫度就可以彈出棧頂并計算結(jié)果因為右邊第一個比它大的溫度已經(jīng)出現(xiàn)了。注意棧里存的是下標(biāo)而不是溫度這樣才能算出隔了多少天。這類找下一個更大元素的問題只要出現(xiàn)下一個更大/更小就應(yīng)該條件反射地想到單調(diào)棧。隊列這邊滑動窗口最大值239用的是單調(diào)隊列思路和單調(diào)棧一脈相承但多了窗口收縮。當(dāng)你發(fā)現(xiàn)自己在窗口滑動時還要反復(fù)找最大值就該意識到需要用一個雙端隊列來維護窗口內(nèi)的候選最大值隊首是當(dāng)前窗口最大值的下標(biāo)每次滑動時先淘汰過期下標(biāo)再維護隊尾的單調(diào)性。把這道題吃透你對用額外結(jié)構(gòu)維護窗口信息的理解會深化不少。2.4 哈希表熱題100里真正的大贏家數(shù)組與哈希能占四分之一的比例不是沒有原因的。兩數(shù)之和1用哈希表做邊遍歷邊查找是空間換時間的標(biāo)準(zhǔn)示范字母異位詞分組49用排序后的字符串當(dāng) key把同構(gòu)詞歸到一起和為 K 的子數(shù)組560用前綴和加哈希表計數(shù)把 O(n^2) 的枚舉壓縮到 O(n)。這三道題放在一起看能提煉出一個通用的思維模式當(dāng)問題需要快速判斷某個值是否出現(xiàn)過或快速統(tǒng)計某個前綴信息的出現(xiàn)次數(shù)時用一個哈希表去記賬幾乎總是良配。而且哈希表題最方便練習(xí)從暴力解到優(yōu)化解的講故事過程——面試官就喜歡聽你怎么把 O(n^2) 改到 O(n)。3. 算法范式部分把題解背成思路3.1 二分答案的邊界哲學(xué)從愛吃香蕉的狒狒說起熱題100里并沒有愛吃香蕉的狒狒這道題但它在很多人的刷題筆記里被標(biāo)記為必刷題單之外必看的補充題——也就是 LeetCode 875 題 Koko Eating Bananas網(wǎng)上也常戲稱它叫愛吃香蕉的狒狒。這道題是理解二分答案的最佳素材。題目不復(fù)雜有一堆香蕉 piles每個 pile 有一定數(shù)量的香蕉狒狒每小時可以吃掉一堆中的任意 k 根如果一堆少于 k 根就吃完這堆去下一堆。問在 h 小時內(nèi)吃完的前提下最慢的吃香蕉速度 k 是多少。樸素做法是從 1 開始逐個試速度直到某個速度能在 h 小時內(nèi)吃完O(max(piles)·n)數(shù)據(jù)一大就超時。二分答案的關(guān)鍵在于發(fā)現(xiàn)單調(diào)性速度 k 越大完成時間越短。所以我們可以二分 k 本身把問題變成給定速度 k能否在 h 小時內(nèi)吃完也就是寫一個 check 函數(shù)def can_finish(piles, h, speed): hours 0 for pile in piles: hours (pile speed - 1) // speed # 向上取整 if hours h: return False return True二分邊界我推薦用左閉右閉加答案收斂的寫法邏輯最不容易出錯def min_eating_speed(piles, h): left, right 1, max(piles) while left right: mid (left right) // 2 if can_finish(piles, h, mid): right mid # 當(dāng)前速度可以嘗試更慢 else: left mid 1 # 當(dāng)前速度不夠快 return left很多人在二分題上反復(fù)翻車問題幾乎都出在邊界mid 用哪種取法、left 和 right 到底誰該跨一步、循環(huán)條件是小于還是小于等于。我的經(jīng)驗是與其記一堆模板不如每次先想清楚兩個問題check(mid) 滿足時答案應(yīng)該往哪邊收斂check(mid) 不滿足時又該往哪邊收斂把這兩個問題想明白邊界自然不會再錯。向上取整的寫法(pile speed - 1) // speed也是一個高頻易錯點直接pile // speed在這道題里會得到錯誤結(jié)果需要特別注意。從這道題延伸出去熱題100里的搜索旋轉(zhuǎn)排序數(shù)組33、在排序數(shù)組中查找元素的第一個和最后一個位置34也都是二分家族成員但它們的二分對象是數(shù)組下標(biāo)判斷條件依賴數(shù)組本身的單調(diào)性或旋轉(zhuǎn)特征。把 愛吃香蕉的狒狒 這類二分答案練熟之后再回頭寫那些下標(biāo)二分你會發(fā)現(xiàn)自己對邊界條件的理解完全不同。3.2 滑動窗口什么時候擴張、什么時候收縮滑動窗口是熱題100里最講道理的一類算法題因為窗口的移動規(guī)則是能推理出來的。核心只有三句話右指針負責(zé)擴張窗口直到窗口不再滿足條件左指針負責(zé)收縮窗口直到窗口重新滿足條件在收縮過程中統(tǒng)計答案。無重復(fù)字符的最長子串3是最經(jīng)典的入門題。用哈希表記錄每個字符最后一次出現(xiàn)的下標(biāo)右指針向右走時如果當(dāng)前字符在窗口內(nèi)出現(xiàn)過就把左指針跳到上一次出現(xiàn)位置的后面然后更新答案。注意這里收縮的是跳躍式收縮比逐步移動左指針更高效。最小覆蓋子串76是滑動窗口里比較難的一道但思路完全一致右指針擴展直到窗口內(nèi)包含了 t 中所有字符然后嘗試收縮左指針只要窗口仍然包含全部所需字符就不斷收縮并更新最短結(jié)果。實現(xiàn)細節(jié)上用兩個計數(shù)器一個記錄 t 中各字符的需求量一個記錄窗口內(nèi)實際數(shù)量再用一個變量統(tǒng)計已滿足條件的字符種類數(shù)這會讓判斷邏輯簡單很多。我見過不少人在這里用雙重循環(huán)去比較兩個哈希表既慢又沒必要——維護一個滿足種數(shù)計數(shù)器就能 O(1) 判斷?;瑒哟翱诘念}目非??简灱毠?jié)尤其是什么時候更新答案是擴張時更新還是收縮時更新無重復(fù)字符最長子串在擴張時更新即可最小覆蓋子串則必須在收縮時更新。這兩類題各做一遍再遇到最長xx子串最短xx子串就有方向了。3.3 動態(tài)規(guī)劃狀態(tài)定義比轉(zhuǎn)移方程更重要很多人在熱題100的動態(tài)規(guī)劃題上卡住不是因為不會寫轉(zhuǎn)移方程而是不知道狀態(tài)該怎么定義。我自己的方法是反過來想在走到第 i 步時題目希望我知道什么信息把這個信息設(shè)成狀態(tài)。拿打家劫舍198來說走到第 i 家時有兩個可能偷這一家那前一家必不能偷不偷這一家那前面可以隨便偷。于是狀態(tài)自然分成兩種寫成一維的話就是dp[i] max(dp[i-1], dp[i-2] nums[i])。這里的dp[i]表示前 i 家能偷到的最大金額。如果一開始想不通把狀態(tài)擴展成二維dp[i][0/1]表示第 i 家不偷/偷的最大金額邏輯會更直白。兩種定義都能過面試時選自己講得最順的。爬樓梯70則更基礎(chǔ)到第 i 階可以從 i-1 階跨一步也可以從 i-2 階跨兩步所以dp[i] dp[i-1] dp[i-2]本質(zhì)就是斐波那契數(shù)列。注意大多數(shù)面試官會在這個題上追問能不能優(yōu)化空間所以提前準(zhǔn)備好滾動變量的寫法非常加分。零錢兌換322是典型的完全背包問題狀態(tài)dp[i]表示湊出金額 i 所需的最少硬幣數(shù)轉(zhuǎn)移時遍歷每種硬幣dp[i] min(dp[i], dp[i-coin] 1)。初始化時把dp[0]設(shè)為 0其余設(shè)為一個大數(shù)。這道題我特別提醒一句遍歷順序很關(guān)鍵。外層循環(huán)遍歷金額、內(nèi)層循環(huán)遍歷硬幣和反過來結(jié)果是一樣的但理解起來前者更直觀建議用一種寫死另一時刻再研究。最長遞增子序列300相對難一些但如果只求長度可以用貪心加二分維護一個數(shù)組 tailstails[i] 表示長度為 i1 的遞增子序列的結(jié)尾最小值遍歷每個數(shù)時二分查找插入位置。這個做法面試中能寫出來是加分項但前提是你要能講清楚它為什么是對的——不能只背代碼。動態(tài)規(guī)劃題在這個題單里占比不低我的建議是先把爬樓梯、打家劫舍、零錢兌換、不同路徑、分割等和子集這五道題吃透它們分別對應(yīng)了一維 DP、二維網(wǎng)格 DP、背包 DP 和可行性 DP覆蓋面基本夠了。3.4 回溯算法一套模板吃透排列組合回溯在熱題100里雖然占比不高但全排列46、組合總和39、子集78、括號生成22這四道題出現(xiàn)頻率很高。回溯的核心是選擇、遞歸、撤銷選擇六字口訣寫成模板就是def backtrack(path, choices): if 滿足結(jié)束條件: 記錄答案 return for option in choices: 做選擇 backtrack(path [option], 更新后的choices) 撤銷選擇關(guān)鍵在更新后的choices怎么定。全排列要的是所有順序所以每次遞歸都要從剩余的沒用過的數(shù)字里選通常用一個 visited 數(shù)組記錄是否用過組合總和不在乎順序而且每個數(shù)可以重復(fù)使用所以遞歸時傳入一個 startIndex保證只從當(dāng)前位置向后取天然避免重復(fù)組合子集則在整個遞歸過程中把所有中間路徑都記錄下來遇到每個元素都面臨選或不選。全排列的去重還有一個很隱蔽的坑如果輸入數(shù)組有重復(fù)元素必須先排序然后在同一層遞歸中跳過和前一個元素相等的分支。判斷條件要寫清楚比如i start_index and nums[i] nums[i-1] and not used[i-1]這類邏輯很多人在這里直接照抄題解結(jié)果不知道為什么面試一問就露餡。我個人練回溯題的經(jīng)驗是先用模板把無重復(fù)全排列跑通然后做組合總和觀察 startIndex 和 used 數(shù)組分別解決什么問題最后做子集體會什么時候記錄答案。三步走完回溯的套路基本就刻進腦子里了。4. 熱題100里最容易被忽略的易錯點4.1 邊界條件左閉右開、空指針與下標(biāo)錯位刷熱題100的過程里你會反復(fù)遇見三類邊界問題。第一類是二分和排序里的左閉右開區(qū)間循環(huán)結(jié)束時 left 和 right 的關(guān)系是什么、mid 會不會越界不同模板答案不一樣我建議固定使用一種并吃透它。第二類是鏈表和樹里的空指針reverse 鏈表時 next 為空、二叉樹遞歸到空節(jié)點時該怎么返回這種位置往往就是空指針異常的爆發(fā)點。第三類是數(shù)組下標(biāo)的錯位滑動窗口里左指針是否包含當(dāng)前字符、和為 K 的子數(shù)組里前綴和數(shù)組的長度是不是 n1這類錯誤很難靠眼睛看出來最好在每個邊界位置手動代入一個短例子試跑。我自己的習(xí)慣是每道題寫完立刻在心里跑三個用例空輸入、只有 1 個元素、最大規(guī)模輸入。這三個用例能幫你在提交前攔下一大半邊界問題比反復(fù)提交等判題要高效得多。4.2 空間復(fù)雜度的隱性要求熱題100里不少題都有空間復(fù)雜度的隱性約束最容易踩坑的是那些要求 O(1) 空間的題。移動零283要求原地操作顏色分類75要求原地排序兩數(shù)之和都能用哈希表通過但除自身以外數(shù)組的乘積238明確要求不使用除法、常數(shù)空間所以只能做前綴積和后綴積的掃描最后用輸出數(shù)組本身來存儲中間結(jié)果。尋找重復(fù)數(shù)287是另一道典型的空間陷阱題。題面里給出 n1 個數(shù)都在 1 到 n 之間要求不能修改數(shù)組且只能用常數(shù)空間。最自然的想法是哈希表但空間不達標(biāo)排序也不行因為會修改數(shù)組。正確的解法要么用二分值域要么用快慢指針找環(huán)。這種看著是哈希題實際是二分/快慢指針題的彎子正是熱題100里最容易拉開差距的地方。做這一類題我建議在動筆前先大聲問自己一句題目有沒有隱含的空間限制沒有的話大膽用哈希表有的話優(yōu)先想想雙指針、原地交換和前綴/后綴思想。4.3 背題解導(dǎo)致的三種假會做我在帶練過程中總結(jié)過很多人刷熱題100刷到后面會產(chǎn)生三種假會做。第一種是換個數(shù)字就不會。熱題100的原題背得滾瓜爛熟但只要把場景換一下、把數(shù)組改成字符串、把最大值改成最小值思路就斷掉了。破解辦法是每做完一道題強迫自己把解法講成一段為什么這樣做的話而不是記住這道題這樣做。第二種是會寫不會說。面試和刷題的最大差別是面試官會追問你為什么要想到用單調(diào)隊列你的二分邊界為什么不會死循環(huán)。如果平時只對著編輯器敲代碼沒有口頭表達訓(xùn)練面試現(xiàn)場很難講清楚。這個問題的解法放在下一章展開。第三種是忘記復(fù)雜度分析。熱題100的題解基本都會標(biāo)時間復(fù)雜度和空間復(fù)雜度但很多人根本不看。這會導(dǎo)致你在面試時被問能不能優(yōu)化時完全沒方向。我的建議是每道題把復(fù)雜度寫在代碼注釋里不是為了記住數(shù)字而是為了逼自己想一遍這里循環(huán)嵌套了幾層、額外開了多大的結(jié)構(gòu)。5. 刷題節(jié)奏、復(fù)盤模板與面試表達訓(xùn)練5.1 三階段刷法從標(biāo)簽刷到亂序刷熱題100總共 100 道我建議不要平均用力按三個階段推進。第一階段按標(biāo)簽刷。先數(shù)組哈希再鏈表接著樹然后雙指針和滑動窗口最后動態(tài)規(guī)劃和回溯。標(biāo)簽集中刷的好處是同一類題連做 5 道之后套路會自動浮現(xiàn)。這一階段的目標(biāo)不是全部做出來而是每道題都能看懂題解并復(fù)現(xiàn)。第二階段亂序刷。當(dāng)你有了一定題量把熱題100打亂順序每天隨機抽 3 到 5 道題不看標(biāo)簽直接做。這一階段訓(xùn)練的是見到問題能自己判斷屬于哪一類的能力也是面試真正需要的。你會發(fā)現(xiàn)亂序時有些題就是想不起來用什么思路這正是好事——暴露了你的薄弱環(huán)節(jié)。第三階段限時模擬。每道題給自己 25 到 30 分鐘超時就看題解但看完題解后必須合上題解自己重寫一遍。這個階段的目的是模擬面試的時間壓力。很多人平時刷題不卡時間面試十幾分鐘寫不出來就緊張所以這種訓(xùn)練很有必要。三個階段的用時我一般是 3:3:2具體看自己基礎(chǔ)調(diào)整?;A(chǔ)弱就把第一階段拉長刷題經(jīng)驗多就早點進第二階段。5.2 復(fù)盤模板讓每道題都留下可遷移的資產(chǎn)刷題不復(fù)盤等于白刷。我復(fù)盤熱題100時每道題都會在筆記里寫下五欄內(nèi)容用了什么數(shù)據(jù)結(jié)構(gòu)為什么選用它核心算法范式是哪一個雙指針、二分答案、DP、回溯、單調(diào)棧等邊界條件里最容易錯的地方時間復(fù)雜度和空間復(fù)雜度這道題能不能抽象成一句更通用的套路話術(shù)舉個例子和為 K 的子數(shù)組560復(fù)盤時可以寫數(shù)據(jù)結(jié)構(gòu)是哈希表范式是前綴和易錯點是前綴和數(shù)組長度和 map 初始值{0:1}復(fù)雜度 O(n)/O(n)套路話術(shù)是遇到連續(xù)子數(shù)組求和優(yōu)先想前綴和再想能不能用哈希表壓縮查找。這些東西攢多了會在你腦子里形成一張題路網(wǎng)。以后看到一道新題你會下意識地想這不就是滑動窗口嗎這不就是單調(diào)棧的變式嗎這種能力不是憑空來的就是復(fù)盤攢出來的。5.3 周賽 430 的啟示競賽與面試題的關(guān)系很多人會問我平時要不要打周賽。我的回答是有空就打但要知道它和面試題的區(qū)別。LeetCode 的周賽數(shù)據(jù)包括最近的周賽 430 場都是在核心知識點之外加入了很多組合技巧和更精細的邊界處理。競賽題更看重臨場速度和思維強度而面試題更看重基礎(chǔ)功底和溝通能力。打周賽最大的價值是讓你在壓力下訓(xùn)練讀題、歸類、套模板的反應(yīng)速度這是平時自己慢慢刷題練不出來的。當(dāng)然如果你周賽永遠只做得出第一題也不必氣餒。我見過很多人第一題都只能磕磕絆絆過但熱題100刷扎實之后周賽二三題也能穩(wěn)定做出來。競賽是檢驗不是目的熱題100才是打底的主線任務(wù)。我個人的建議是熱題100三階段走完再開始系統(tǒng)性打周賽順序不要反。5.4 面試講題從暴力解到優(yōu)化解的表達路徑面試講題和私下做出來是兩回事。私下里你可以直接寫最優(yōu)解面試時我更推薦按這個順序講先講暴力解把復(fù)雜度說清楚然后指出暴力解的瓶頸再引出優(yōu)化思路最后寫最優(yōu)解并再次完成復(fù)雜度分析。這里的邏輯不是讓你多說廢話而是給面試官一個理解你的思考過程的路徑。用簡單的例子說求兩數(shù)之和暴力解是雙重循環(huán)瓶頸在于每次都要遍歷查找另一個數(shù)于是自然引出哈希表邊遍歷邊查詢。當(dāng)你把這個過程講順面試官不僅看出你會做這道題還會覺得你是一個會思考的人。講題時還有幾個小技巧先說結(jié)論再解釋原因比如這題我用二分因為速度有單調(diào)性寫代碼前說邊界比如注意這里要處理空鏈表寫完代碼快速手動跟一個短例子把每一步的狀態(tài)念出來。這些習(xí)慣平時刷題時不練面試時很難臨時發(fā)揮出來。寫在最后這篇 LeetCode 熱題100 的總結(jié)到目前為止主要把題型分布、數(shù)據(jù)結(jié)構(gòu)高頻套路、算法范式、易錯點和刷題方法講了一遍后續(xù)我會沿著幾個方向繼續(xù)更新把每類題的經(jīng)典變式挑出來做對比串講把熱題100里容易混淆的成對題目比如最大子數(shù)組和與乘積最大子數(shù)組專門拆開分析還會把周賽中出現(xiàn)的和熱門100題同源的高頻競賽題補充進來。我自己的體會是熱題100刷得好的標(biāo)準(zhǔn)不是全都會默寫而是看到新題能快速判斷它屬于哪個套路并且能在 20 分鐘內(nèi)完成從思路到代碼的轉(zhuǎn)化。這個標(biāo)準(zhǔn)我刷了三遍才勉強達到。刷題這件事沒有捷徑但方向?qū)α舜_實可以少走很多彎路。如果你按照這篇總結(jié)的節(jié)奏去刷我相信四到六周內(nèi)能看到明顯的題感變化。后續(xù)更新見。