的考察邏輯與備考路徑)
2023年秋招小紅書算法崗第一批筆試我至今還記得打開筆試系統(tǒng)那一刻的感受題量比預想中大題型比預想中雜有些題目看起來像是八股但仔細一讀又全是業(yè)務味。作為經(jīng)歷過完整秋招、最終拿到幾家大廠算法offer的過來人這篇復盤我拖了很久才寫就是想把自己從“接到筆試通知”到“提交試卷”再到“復盤整理”的全過程盡量還原成一套可復用的準備路徑。如果你正在準備算法崗的筆試尤其是互聯(lián)網(wǎng)內(nèi)容平臺方向的公司這篇文章應該能幫你少走不少彎路。先說結(jié)論小紅書算法崗的筆試不是純刷題平臺那種“四道Hard題定生死”的風格而是“算法題打底 機器學習/深度學習基礎 業(yè)務場景分析”的組合拳。它的篩選邏輯很明確——既要你代碼寫得動也要你原理講得清還要你對業(yè)務場景有感覺。下面我從試卷的整體結(jié)構(gòu)、核心算法題的復盤、非算法題的考察重點、提交前的自查清單、以及后續(xù)準備方向的調(diào)整這幾個維度逐一展開。1. 從收到筆試通知到打開答卷這批題到底在考什么1.1 筆試平臺與答題節(jié)奏先交代一下客觀情況。2023年秋招的筆試大多通過??途W(wǎng)或者賽碼網(wǎng)進行小紅書這批用的是其中一家支持本地IDE調(diào)試后粘貼代碼也支持在線編輯。整場筆試時長一般在90到120分鐘題型分布大致是單選/多選題、2到4道編程題、若干道簡答或設計題。這個結(jié)構(gòu)意味著什么意味著你沒法用“只刷LeetCode”的方式去應對因為算法題只是其中一個環(huán)節(jié)選擇題和簡答題同樣占分而且往往是決定能否進入面試的關鍵分水嶺。我當時的節(jié)奏是這樣的先花3到5分鐘快速瀏覽全部題目判斷每道題的難度和熟悉度。編程題先挑有思路的做不會的標記下來回頭再想選擇題和簡答題放在編程題之后集中處理。這個策略幫我避免了一個很常見的坑——在一道難題上死磕40分鐘結(jié)果后面的基礎題沒時間寫。筆試不是競賽不要求你每道題都得滿分但要求你在有限時間里拿到盡可能多的分數(shù)這是一種典型的“分數(shù)最優(yōu)”思維。1.2 熱搜詞背后的考點雷達一張知識點地圖筆試結(jié)束之后我習慣性地去復盤知識點分布。有意思的是如果把這個階段搜索熱度較高的一些算法詞拉出來看基本就是一張算法崗筆試的考點雷達圖。它們大致可以歸成這幾類數(shù)據(jù)結(jié)構(gòu)與基礎算法KMP算法與next數(shù)組、排序、堆排序、快速冪、二分、貪心、前綴和、剪枝。機器學習KNN、聚類、XGBoost、強化學習、BM25、異常檢測、特征工程。深度學習與數(shù)學基礎KL散度、ELBO、圖像分類、EVA-02、CNN/Transformer以及拉普拉斯銳化、音頻重采樣等信號處理概念。經(jīng)典優(yōu)化與狀態(tài)估計粒子群算法、模擬退火、卡爾曼濾波、PID、Minimax。我把它整理成一張表格方便按圖索驥考察板塊高頻知識點常見出題方式備考優(yōu)先級數(shù)據(jù)結(jié)構(gòu)KMP、堆、二分、貪心、前綴和編程題、選擇高機器學習KNN、聚類、XGBoost、過擬合、AUC選擇、簡答高深度學習注意力機制、KL散度、ELBO、圖像分類選擇、簡答中高經(jīng)典算法粒子群、模擬退火、卡爾曼濾波、PID選擇、場景分析中業(yè)務場景推薦鏈路、冷啟動、AB實驗簡答、設計高這張表不是用來背的而是用來自測的。拿出一張紙把每個知識點默寫一遍能寫清楚它的思想、適用場景、復雜度說明你過關了寫不出來說明這里還有盲區(qū)。很多人在筆試前把精力全壓在LeetCode上結(jié)果選擇題問“KL散度不對稱性怎么體現(xiàn)”直接懵了非常可惜。2. 四道算法題復盤從暴力解到最優(yōu)解的思考路徑算法題永遠是最核心的拉分項。這批筆試里的大題難度介于LeetCode Medium到Hard之間題型不算偏但不少題都隱含了業(yè)務場景的設置。下面我按當時的復盤筆記挑四類高頻題目做拆解。注意我不會直接貼“真題”而是把它抽象成題目原型重點是還原思考路徑。2.1 字符串匹配與最小循環(huán)節(jié)KMP的next數(shù)組不是背出來的第一類高頻題是字符串處理典型原型是給定一個字符串s判斷它是否由某個子串重復拼接而成如果是輸出最小循環(huán)節(jié)長度。這個題在LeetCode上有類似題目比如重復子字符串問題主流解法就是KMP。我當時的初始想法很樸素枚舉所有可能的循環(huán)節(jié)長度L判斷s[i] s[i % L]對所有i是否成立時間復雜度O(n^2)在n到10^5級別的時候必掛。于是我想到了KMP。KMP的核心是前綴函數(shù)也就是next數(shù)組。對于模式串pnext[i]表示p[0...i]的最長相等真前后綴長度。利用next數(shù)組最小循環(huán)節(jié)長度的判斷就變成了計算字符串s的next數(shù)組即前綴函數(shù)。設L n - next[n-1]注意這里取決于next數(shù)組的下標定義。如果n % L 0那么L就是最小循環(huán)節(jié)長度否則不存在循環(huán)節(jié)答案就是n本身。這個過程的關鍵在于為什么n - next[n-1]就是候選循環(huán)節(jié)長度因為如果整個字符串s存在循環(huán)節(jié)那么它的最長相等前后綴長度一定是n - L。這個結(jié)論可以自己畫圖推一遍一個周期串“abcabcabc”的最長相等前后綴是“abcabc”長度為6n9n - 6 3正好是循環(huán)節(jié)長度。這個推導過程比記結(jié)論重要得多因為筆試選擇題很容易變形考。再補一個熱門的考察細節(jié)模式串p abacaba的next數(shù)組怎么手算。i0字符anext[0] 0因為沒有真前后綴。i1字符串a(chǎn)b最長相等前后綴長度0next[1]0。i2字符串a(chǎn)ba最長相等前后綴是a長度1next[2]1。i3字符串a(chǎn)bac前輟a和后綴c不同長度0next[3]0。i4字符串a(chǎn)baca最長相等前后綴是a長度1next[4]1。i5字符串a(chǎn)bacab最長相等前后綴ab長度2next[5]2。i6字符串a(chǎn)bacaba最長相等前后綴是aba長度3next[6]3。所以p abacaba的next數(shù)組是[0, 0, 1, 0, 1, 2, 3]。這個手算過程在筆試中經(jīng)常以選擇題形式出現(xiàn)不要只看書上的結(jié)論一定要自己多找?guī)讉€串練一遍。KMP的復雜度是O(nm)相比暴力匹配的優(yōu)勢在模式串很長、重復匹配很多的時候非常明顯這也是它在搜索、推薦、NLP場景里被廣泛應用的原因。2.2 任務調(diào)度與貪心堆優(yōu)化貪心不是猜交換論證才是底氣第二類高頻題是任務調(diào)度類。典型原型是給定n個任務每個任務有處理耗時time[i]和截止時間deadline[i]每個任務耗時相同權(quán)重求最多能完成多少個任務。這個問題我在筆試里遇到過好幾個變體解法都是同一個套路按截止時間排序用小根堆或者大根堆維護已選任務如果當前累計耗時超過當前任務的截止時間就把已選任務中耗時最大的任務丟出去。很多同學到這里會疑惑為什么按截止時間排序為什么移除的是耗時最大的任務而不是當前任務我當時的理解是這樣的按截止時間排序是經(jīng)典的“最緊迫任務優(yōu)先”策略。對于一組任務如果截止時間較早的任務都無法完成那截止時間更晚的任務更不可能在這個時間窗口內(nèi)完成所以先處理截止早的任務是合理的。當累計耗時超了我們需要從已選任務中刪掉一個。為了“損失最小”應該刪掉耗時最大的那個因為刪掉它之后節(jié)省出來的時間最多能容納更多任務。這個推理可以用交換論證嚴格證明任何最優(yōu)解都可以調(diào)整成這種貪心選擇的形式而不改變?nèi)蝿諗?shù)量。復雜度上排序是O(nlogn)堆的插入和刪除都是O(logn)整體O(nlogn)在n10^5級別下沒有任何壓力。踩坑提醒題目里一定要看清任務之間是否獨立。如果任務之間有依賴關系A必須在B之前完成那這就變成了拓撲排序調(diào)度的組合題上面的貪心策略就不成立了。我當時就因為在讀題時默認任務獨立差點把一道帶依賴的任務題當成普通貪心做了幸好檢查時發(fā)現(xiàn)題目里有一句“某些任務依賴前置任務完成”及時切換思路。2.3 前綴和與雙指針O(n^2)到O(n)的優(yōu)化是怎么想到的第三類高頻題是數(shù)組類典型原型是給定一個長度為n的非負整數(shù)數(shù)組nums和一個目標值target求和大于等于target的連續(xù)子數(shù)組的最短長度。這個題在LeetCode上是209題很經(jīng)典。第一思路肯定是暴力枚舉所有連續(xù)子數(shù)組計算區(qū)間和然后比較O(n^2)復雜度。然后想到用前綴和優(yōu)化區(qū)間和的計算把內(nèi)層循環(huán)從求和變成一次減法但依然是O(n^2)。真正能到O(n)的做法是兩個前綴和二分。因為數(shù)組非負所以前綴和數(shù)組是單調(diào)遞增的。我們可以枚舉左端點二分查找第一個使得區(qū)間和≥target的右端點復雜度O(nlogn)。雙指針滑動窗口。維護窗口的左右指針窗口內(nèi)和小于target就擴展右指針大于等于target就嘗試收縮左指針同時更新答案。每個元素最多被訪問兩次復雜度O(n)。我當時寫的雙指針版本大致是這樣的def minSubArrayLen(target: int, nums: list[int]) - int: n len(nums) left 0 window_sum 0 ans float(inf) for right in range(n): window_sum nums[right] while window_sum target: ans min(ans, right - left 1) window_sum - nums[left] left 1 return 0 if ans float(inf) else ans這題最佳解法為什么是滑窗而不是二分因為滑窗在遍歷過程中既更新了左右邊界又同步維護了區(qū)間和省掉了二分查找的logn因子在數(shù)據(jù)量極大時更穩(wěn)妥。而且這種“看到單調(diào)性就想到優(yōu)化”的思路在后續(xù)很多二分類似題里都是通用的——比如“找到AUC最大的閾值區(qū)間”“找到滿足轉(zhuǎn)化目標的最短投放窗口”等本質(zhì)都是在有序序列上做指針移動。2.4 TopK問題堆、快速選擇與數(shù)據(jù)流場景第四類高頻題是TopK問題尤其是“數(shù)據(jù)流中動態(tài)求第K大元素”這種變體。原型題目設計一個類支持add(val)操作并隨時返回當前所有元素中第K大的值。這個題LeetCode 703算法崗考它的頻率極高因為它能同時考察堆、排序、二分多個知識點還經(jīng)常和推薦系統(tǒng)的“熱門內(nèi)容TopK”業(yè)務場景結(jié)合。我的思路演進是這樣的全局排序每次add之后重新排序取第K個時間復雜度O(m log m)m為當前元素個數(shù)。數(shù)據(jù)量小的時候無所謂數(shù)據(jù)流一大就廢了。最小堆維護一個大小為K的最小堆堆頂就是第K大的元素。add時如果堆的大小小于K直接入堆否則如果新元素比堆頂大就彈出堆頂、加入新元素。這樣每次add的復雜度是O(logK)空間O(K)非常優(yōu)雅??焖龠x擇如果只是一次性查詢而不是持續(xù)維護可以用快速選擇算法平均O(n)找到第K大元素但最壞O(n^2)并且不能很好地處理流式數(shù)據(jù)。筆試里我強烈建議直接用堆因為它的復雜度穩(wěn)定、代碼短、不容易寫錯。如果考官后續(xù)追問“內(nèi)存不夠怎么辦”再說分桶、小頂堆大頂堆組合或者哈希計數(shù)等方式。另外注意TopK有兩個變種——第K大和第K小對應的堆類型正好相反寫代碼前先確認清楚。3. 非算法題里的能力考察機器學習、深度學習與數(shù)學基本功3.1 機器學習概念題不是背八股而是考你有沒有真正理解小紅書這批筆試的選擇題和簡答題里機器學習相關的比重很高。最常出現(xiàn)的是這幾類KNN的投票機制和距離度量、K-Means的初始化和收斂、過擬合的判別與緩解、AUC和LogLoss的適用場景、樣本不均衡的處理方式、冷啟動問題。這些問題看起來像八股但出題人往往會換一個業(yè)務場景來包裝。比如“新用戶沒有任何行為數(shù)據(jù)怎么給他做內(nèi)容推薦”本質(zhì)就是在考冷啟動。我的回答套路是三步先給結(jié)論再展開原理最后結(jié)合場景舉例。比如KNN結(jié)論是“基于鄰居標簽投票的分類方法”原理是“通過距離度量找到最近的K個樣本以多數(shù)投票決定類別”場景舉例是“在用戶相似度召回中可以用KNN的思路找到相似用戶再用協(xié)同過濾生成推薦候選”。這樣回答既有信息量又體現(xiàn)了業(yè)務感覺。另外抽樣評估指標也很重要。AUC是排序能力的度量適合正負樣本不均衡的場景LogLoss是對概率預測質(zhì)量的度量適合需要校準概率的場景。如果你只是說“AUC越大越好”那是背答案如果你能說“AUC對閾值不敏感適合點擊率預估中正樣本極其稀疏的局面”那才是真的理解。3.2 深度學習與概率基礎從KL散度到ELBO為什么數(shù)學是算法崗的分水嶺這批筆試里出現(xiàn)了一個很值得注意的考點KL散度與ELBOEvidence Lower Bound的關系。很多同學一看這題就懵覺得這是生成模型才用的東西跟推薦算法有什么關系。但仔細想VAE、擴散模型、甚至一些多模態(tài)模型的訓練目標都離不開這個數(shù)學基礎。筆試考它本質(zhì)是在篩選“能讀得懂最新論文”的候選人而不只是會調(diào)包調(diào)參的人。我建議用這個通俗理解方式去消化KL散度衡量的是兩個概率分布之間的差異它是不對稱的也就是說KL(P||Q)不等于KL(Q||P)這一點經(jīng)常被出成選擇題。ELBO則是對數(shù)似然log p(x)的下界它把難以直接計算的log p(x)轉(zhuǎn)化為“重構(gòu)誤差先驗正則項”的形式讓模型可以通過最大化ELBO來近似最大化似然。這就好比你想知道一個復雜機器的真實功率log p(x)但沒法直接測于是你用一個簡化模型q(z)去逼近它并不斷優(yōu)化這個逼近過程ELBO就是那個“逼近得好不好”的度量。這類題沒有捷徑必須自己動手推一遍VAE的損失函數(shù)推導。只背“ELBO 重構(gòu)損失 - KL散度”這個結(jié)論一到變式題就露餡。我備考時花了整整兩天的時間把KL散度的定義、ELBO的推導、重參數(shù)化技巧完整手推了一遍之后的筆面試里遇到相關問題基本都能接住。3.3 經(jīng)典算法場景題粒子群、卡爾曼濾波、PID不是沒用的冷知識熱搜詞里出現(xiàn)了粒子群算法、模擬退火算法、卡爾曼濾波算法、PID算法很多人覺得這些是控制論或者運籌學的內(nèi)容算法崗筆試考這些是不是超綱了其實不然。這些算法體現(xiàn)的是一個候選人的知識廣度以及“在真實系統(tǒng)里做決策優(yōu)化”的能力。我整理過這些算法的適用場景對比算法本質(zhì)典型應用場景復雜度特點粒子群算法群體智能搜索連續(xù)參數(shù)優(yōu)化、特征選擇、超參搜索每輪評估所有粒子O(N*D)模擬退火概率型局部搜索組合優(yōu)化、布局規(guī)劃、離散決策迭代次數(shù)較多但單次評估便宜卡爾曼濾波最優(yōu)狀態(tài)估計軌跡預測、傳感器融合、視頻目標跟蹤線性復雜度適合在線計算PID控制反饋控制播放器碼率控制、流量調(diào)控、系統(tǒng)穩(wěn)定性O(1)幾乎無計算壓力Minimax博弈樹搜索棋類AI、對抗策略、游戲平衡指數(shù)級需要剪枝優(yōu)化如果選擇題里問“視頻播放卡頓時如何平滑碼率”那答案思路一定是卡爾曼濾波或PID——因為這類問題本質(zhì)是“用帶噪聲的觀測實時估計真實狀態(tài)并做出平滑控制”。再比如“在超參搜索時如何平衡探索和利用”粒子群和模擬退火都是合理的選項要能說清楚它們各自怎么跳出局部最優(yōu)。這些不是需要你手寫完整實現(xiàn)的知識但一定要在場景題里認得出、選得對。3.4 業(yè)務場景簡答題召回、精排、AB實驗的答題框架小紅書這類內(nèi)容平臺的業(yè)務場景簡答題基本繞不開推薦鏈路。我當時遇到的問題是圍繞“如何評估一次推薦策略的上線效果”展開的要求給出方案設計。我的回答框架是這樣的首先明確評估目標——是提升點擊率、停留時長、還是關注轉(zhuǎn)化率不同目標對應不同指標然后設計AB實驗說明分流方式用戶級分流還是請求級分流實驗組和對照組要保證同分布接著確定核心指標和護欄指標比如核心指標是人均點擊次數(shù)護欄指標是內(nèi)容舉報率不能上升最后是顯著性檢驗和上線決策標準比如p值低于0.05且效果量達到預期閾值才允許全量。這類簡答題沒有標準答案但框架完整、邏輯清晰、業(yè)務感強的回答比堆砌術(shù)語更容易拿高分。我在筆試前專門整理了一個“推薦系統(tǒng)問題回答模板”從問題拆解、候選方案、評估方式、風險控制四個維度組織答案筆試的時候直接套結(jié)構(gòu)效率高很多。4. 提交之前最該檢查的細節(jié)邊界、復雜度與平臺規(guī)則4.1 邊界條件與平臺規(guī)則筆試題最容易在細節(jié)上翻車筆試和平時刷題最大的不同在于平臺判題是“黑盒”的。你自己本地跑通了幾個用例不代表提交后能AC。我印象最深的一次是在一道數(shù)組題里忽略了輸入數(shù)組長度為1的情況結(jié)果在平臺上的第一個隱藏用例就掛了。那種感覺非常絕望因為你根本看不到具體是哪個邊界條件出了問題。所以我的經(jīng)驗是每道題寫完先停下來問自己三個問題——數(shù)組為空怎么辦數(shù)組長度是1怎么辦目標值可能是負數(shù)或0嗎如果涉及大數(shù)運算還要考慮整型溢出問題Python還好Java和C選手尤其要注意Long的使用。另外??途W(wǎng)這類平臺經(jīng)常需要自己處理多組輸入有些題要求讀完整行而不是單個token輸出時注意換行和空格這些細節(jié)看似簡單但每年都有大量人因為格式問題被判0分。4.2 復雜度的自我評估提交之前先算清楚提交代碼之前一定要先估算一下最壞情況下的時間復雜度和空間復雜度。一個簡單的準則如果n 10^3O(n^2)基本可以接受。如果n 10^5O(n^2)大概率超時必須優(yōu)化到O(n log n)或O(n)。如果n 10^7O(n)可能是極限盡量考慮O(log n)或O(1)的解法。涉及遞歸時注意Python默認遞歸深度只有1000深搜類的題最好改成迭代或者設置sys.setrecursionlimit。我當時有一道題一開始寫的是O(n^2)暴力提交前自測時發(fā)現(xiàn)n給到了10^5果斷重寫。雖然重寫花了十幾分鐘但保住了整道題的分數(shù)。這個“提交前復雜度假死”的步驟應該像系安全帶一樣成為肌肉記憶。4.3 本地調(diào)試與在線評測的差異從TLE到AC的排查思路還有一個高頻的翻車點是本地IDE和在線評測環(huán)境不一致。最常見的問題是本地用了Python 3.9的語法特性比如dict的合并操作符|但線上環(huán)境是Python 3.8直接語法報錯。所以筆試前一定要確認目標平臺支持的Python版本盡量寫“保守”代碼不要用太新的語法特性。如果提交后遇到TLE超時不要盲目優(yōu)化常數(shù)先把自己的算法復雜度再算一遍。TLE往往不是常數(shù)問題而是算法量級錯了。比如KMP寫成了暴力匹配堆排序?qū)懗闪嗣看闻判蜻@些都是量級錯誤再怎么優(yōu)化局部也救不回來。遇到TLE最優(yōu)做法是冷靜下來重新審題、換解法而不是在原有代碼上做無意義的微調(diào)。5. 復盤后的三點體會對后續(xù)筆面試的實質(zhì)幫助筆試結(jié)束后我花了兩天時間做完整復盤不只是記錄對錯而是把所有題目按知識點重新分類建了一個自己的錯題和知識圖譜。這個過程帶來的收益遠不止一場筆試而是直接改變了后續(xù)所有筆面試的備考策略。第一點體會是算法題一定要練“思考路徑”而不是“背答案”。我看到很多同學刷了幾百道題遇到新題還是不會原因就是他只記住了“這題用DP”但沒想明白“為什么這題能用DP、狀態(tài)怎么定義、轉(zhuǎn)移方程怎么推”。我之后每次刷題都強制自己在紙上寫三行字暴力思路是什么、瓶頸在哪、怎么優(yōu)化。這個習慣讓我在三面手撕代碼的環(huán)節(jié)里明顯比對手穩(wěn)。第二點體會是機器學習原理的深度比廣度重要。小紅書這批筆試讓我意識到光是“知道AUC是什么”不夠要能推AUC的計算公式、能解釋它為什么對閾值不敏感、能說明它在樣本不均衡時的表現(xiàn)。于是我花時間把邏輯回歸、Softmax、AUC、KL散度、注意力機制這些高頻原理全部手推了一遍后面面試里遇到手推損失函數(shù)梯度的題目基本都能應對自如。第三點體會是業(yè)務場景題要多積累答題框架但不要背話術(shù)。如果你提前準備過“新用戶冷啟動怎么做”“推薦評估指標體系怎么搭”這類問題的結(jié)構(gòu)化回答筆試時就能快速組織答案。但如果你只是背了幾個專業(yè)術(shù)語就往上堆判卷人一眼就能看出來。真正有用的是建立一個“拆解問題-給出方案-評估效果-控制風險”的思維模型然后往里填充具體的業(yè)務理解。最后再分享一個筆試后的小技巧無論考得好不好當天晚上趁記憶還熱乎立刻寫下自己能回憶起的每一道題和當時的解題思路。這份“熱乎復盤”比你過一周后再整理要有效得多因為它保存了大量細節(jié)——包括你做錯時的第一反應、卡住的位置、檢查時關注的邊界條件。這些細節(jié)才是下一場筆試真正能用的彈藥。我的經(jīng)驗是能走到最后的候選人通常在每一場筆試后都做了這件事區(qū)別只在記錄的深度和重構(gòu)的認真程度。