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