
2023年秋招那會兒我印象最深的一場筆試就是飛豬的算法崗。說實話飛豬的筆試題量不算大但每道題都出得挺有水平既能篩掉基礎不牢的人又能看出候選人有沒有工程落地的感覺。當時我刷了一圈面經發現大家吐槽最多的就是“看似常規實則處處是坑”。這篇文章就把我當時參加飛豬2023屆秋招算法崗筆試的全過程掰開揉碎講一遍包括題型分布、考了哪些算法、正確的破題思路以及我踩過的坑。如果你正在準備大廠算法崗或者想了解阿里的算法崗筆試風格這篇應該能幫你少走不少彎路。飛豬算法崗筆試屬于典型的“基礎算法 機器學習原理 業務場景設計”組合和純刷題型的筆試有明顯區別。它不會一味考難題偏題但會在很多看似普通的考點上深挖細節比如KMP算法里next數組的手算、概率題里的公式推導、以及對模型選型的理解。這背后其實反映了一件事算法崗不只是要會寫代碼更要懂算法原理、能結合業務做取舍。下面我按模塊拆解把值得說的細節和經驗都放進去。1. 筆試整體認知與題型拆解1.1 飛豬算法崗筆試到底考什么先給沒參加過的人還原一下現場。飛豬2023屆秋招算法崗筆試是在統一的在線筆試平臺上進行的總共約120分鐘題目構成大致如下單選題/多選題覆蓋機器學習基礎、概率統計、數據結構與算法常識大概10到15道。編程題2到3道難度從LeetCode中等偏簡單到中等偏難不等核心考點集中在字符串、動態規劃、圖論和排序。簡答/設計題1道業務場景題通常會給一個飛豬的業務場景比如旅行推薦、酒店價格預測要求寫出算法思路或技術方案。這個題型組合很典型但也有不少同學栽在時間分配上。選擇題看著簡單實際很容易糾結編程題如果第一道卡太久后面的題基本就沒時間看。我當時就是先快速掃了一遍所有題目把選擇題里拿不準的標記出來優先做編程題里最有把握的一道最后再回頭啃選擇題。這個策略不一定最優但至少能保證“該拿的分不丟”。1.2 考題背后的考察邏輯如果你只是把這當成一場普通的算法刷題考試那就理解偏了。飛豬算法崗筆試的每類題目都在測不同的能力數據結構與算法題考察代碼基本功、復雜度的敏感度、邊界條件的處理。機器學習原理題考察是否真的理解模型原理而不是只會調包。比如KL散度、ELBO、K-Means這些概念平時可能只是“聽過”筆試卻要你推導或計算。業務場景設計題考察工程落地思維。飛豬的業務場景和“旅行”“交易”“推薦”“定價”相關能不能把算法和具體業務結合是拉開差距的地方。我當時在準備階段反復提醒自己刷題只是底線真正決定上限的是對算法本質的理解。就像KMP算法的next數組很多人能背代碼但真讓你手推一遍“abacaba”的next數組估計不少人會卡殼。筆試不考背代碼考的就是你能否在紙面上把邏輯理清楚。2. 數據結構與算法高頻考點逐項拆解2.1 KMP算法與next數組一道題能卡住一半人先說KMP。2023年秋招算法崗筆試里字符串匹配相關的高頻考點就是KMP尤其是next數組的手算。筆試那道題我記得很清楚給出模式串 p abacaba要求寫出 next 數組。這道題看起來簡單但場內至少有一半人栽在了定義上。next數組的定義在不同教材里有兩種約定一種表示“當前字符匹配失敗后跳轉的位置”另一種表示“當前字符之前的最長相同前綴后綴長度”。飛豬筆試采用的是后者next[i] 表示 p[0..i-1] 的最長相同前綴后綴長度。也就是說next[0] -1next[1] 0然后逐個遞推。手推過程可以這樣拆解next[0] -1約定值next[1] 0長度為1的子串沒有真前后綴對于 i 2前綴 p[0..1] ab最長相等前后綴長度為0所以 next[2] 0對于 i 3前綴 p[0..2] aba最長相等前后綴是 a長度1所以 next[3] 1對于 i 4前綴 p[0..3] abac沒有相等前后綴next[4] 0對于 i 5前綴 p[0..4] abaca最長相等前后綴是 a長度1next[5] 1對于 i 6前綴 p[0..5] abacab沒有相等前后綴next[6] 0對于 i 7前綴 p[0..6] abacaba最長相等前后綴是 aba長度3next[7] 3所以答案就是 [-1, 0, 0, 1, 0, 1, 0, 3]。如果考場里直接給這個結果可能不到5分鐘就能寫完。但我當時看到很多人還在用暴力法一個個比較前后綴這就是基本功的差距。順便放一個標準的KMP匹配代碼C版本方便你對照理解#include vector #include string using namespace std; vectorint buildNext(const string p) { int m p.size(); vectorint next(m); next[0] -1; int j 0, k -1; while (j m - 1) { if (k -1 || p[j] p[k]) { j; k; next[j] k; } else { k next[k]; } } return next; } int kmpSearch(const string s, const string p) { int n s.size(), m p.size(); vectorint next buildNext(p); int i 0, j 0; while (i n j m) { if (j -1 || s[i] p[j]) { i; j; } else { j next[j]; } } if (j m) return i - j; return -1; }2.2 排序與TopK別只會調sort排序算法幾乎每次筆試都會碰見但飛豬不會直接讓你寫一個冒泡排序完事而是會結合數據量、穩定性、內存限制來考。選擇題里經常有“以下哪個排序算法是穩定的”“堆排序的時間復雜度是多少”“40億個數找最大的100個用什么方法”這類問題。我整理了一個高頻對比表筆試前可以快速過一遍排序算法平均時間復雜度最壞時間復雜度空間復雜度穩定性冒泡排序O(n^2)O(n^2)O(1)穩定選擇排序O(n^2)O(n^2)O(1)不穩定插入排序O(n^2)O(n^2)O(1)穩定快速排序O(n log n)O(n^2)O(log n)不穩定歸并排序O(n log n)O(n log n)O(n)穩定堆排序O(n log n)O(n log n)O(1)不穩定那道“40億個數找TopK”的題最優解不是全局排序而是維護一個大小為K的小頂堆。時間復雜度是O(n log K)空間O(K)。如果內存裝不下全部數據就用外部排序堆。這個點考察的是對海量數據場景的敏感度飛豬有大量用戶行為日志這類問題不是純理論是真會遇見。2.3 貪心、動態規劃與快速冪筆試實戰套路動態規劃和貪心在編程題里出現頻率極高。飛豬筆試第二道編程題我當時遇到的是區間調度變體給定若干個帶權活動每個活動有開始時間、結束時間和收益選擇不沖突的活動使總收益最大。這題貪心解不適用因為帶權后局部最優不等于全局最優必須用動態規劃按結束時間排序設 dp[i] 表示前 i 個活動能獲得的最大收益轉移時用二分查找找到“最后一個結束時間小于當前活動開始時間”的活動。這類題的通用破題套路是先判斷是貪心還是DP——如果局部最優能達到全局最優就選貪心否則考慮DP。判斷完之后寫狀態轉移時重點關注“不選當前元素的情況”很多人丟分都丟在遺漏 dp[i-1] 這個不選分支。快速冪也是筆試的常客。比如計算 a^b mod mb 可以達到 10^18 級別。Python 里可以直接 pow(a, b, m)但筆試選擇題會要求你判斷時間復雜度或者讓你填充代碼。模板如下def fast_pow(a, b, m): res 1 a % m while b 0: if b 1: res (res * a) % m a (a * a) % m b 1 return res快速冪的核心思想是把指數折半把冪運算從 O(b) 降到 O(log b)。同樣的思路還可以用在矩陣快速冪、斐波那契數列求第 n 項等場景。2.4 圖論與搜索Dijkstra、二分圖HK算法圖論基礎算法每年都有。飛豬業務里涉及大量路徑規劃、運籌優化所以 Dijkstra 這類最短路算法屬于必須掌握的。筆試真題里有一道題需要求一個無向加權圖中從起點到終點的最短路徑數據范圍不算大用優先隊列優化后的 Dijkstra 可以輕松通過。Dijkstra 的實現其實有固定的套路import heapq def dijkstra(graph, start): n len(graph) dist [float(inf)] * n dist[start] 0 pq [(0, start)] while pq: d, u heapq.heappop(pq) if d dist[u]: continue for v, w in graph[u]: if dist[u] w dist[v]: dist[v] dist[u] w heapq.heappush(pq, (dist[v], v)) return dist另外一個比較容易被忽視的是二分圖相關的算法。熱搜詞里的HK算法Hopcroft-Karp算法就是二分圖最大匹配的優化版本核心思想是用BFS構建增廣路徑層級圖再用DFS尋找增廣路時間復雜度比匈牙利算法的O(VE)優化到O(E√V)。筆試一般不要求你手寫HK但選擇題可能會問匈牙利算法和HK的區別或者給一個二分圖問最大匹配數。知道“為什么用HK——減少增廣路的搜索次數”就夠了。3. 機器學習與智能算法筆試中的“算法”不只是數據結構3.1 經典ML原理KNN、聚類、邏輯回歸、集成學習飛豬算法崗筆試很大一部分選擇題和簡答題會落在機器學習基礎。這些題不像編程題那么費腦但特別考驗概念是否扎實。我當時遇到的幾個高頻考點KNN的K值影響、K-Means的收斂條件、邏輯回歸的損失函數推導、XGBoost和GBDT的區別。KNN這題問的是“K值增大時模型的偏差和方差如何變化”。答案是K值增大模型變得越簡單偏差增大、方差減小。這個反直覺的點很常考因為很多人直覺認為“樣本用得越多越準”但實際上K太大時會把距離很遠的樣本也納入投票導致邊界過于平滑。K-Means的題則經常問“初始k個中心點如何選擇”。標準答案是隨機選擇但隨機選擇容易陷入局部最優所以實際工程會用K-Means先隨機選第一個中心點再按距離平方加權概率選擇后續中心點讓初始中心點盡可能分散。這個細節在面試里也經常被追問。邏輯回歸那邊手寫梯度下降更新公式是常規操作。邏輯回歸的損失函數是交叉熵L -(1/N) * Σ [y_i * log(p_i) (1 - y_i) * log(1 - p_i)]其中 p_i 1 / (1 exp(-w·x_i))。對 w 求梯度后得到?L/?w (1/N) * Σ (p_i - y_i) * x_i所以梯度下降更新就是 w : w - lr * (1/N) * Σ (p_i - y_i) * x_i。考場里能寫出這一步基本就能說明你是理解邏輯回歸而不是只會 import。集成學習這塊飛豬筆試比較偏愛“隨機森林和GBDT的區別”。一個核心區別是隨機森林是Bagging并行訓練多棵樹然后投票或平均GBDT是Boosting串行訓練每棵樹擬合前面的殘差。XGBoost在GBDT基礎上加了二階泰勒展開、正則項和列采樣訓練速度和精度都更好。這類題不需要你寫公式推導但需要能說清楚“為什么”。3.2 概率與信息論KL散度與ELBO的推導套路KL散度和ELBO是算法崗筆試中偏難的一類題。很多人看到這兩名詞就頭大但飛豬2023年筆試確實考了而且不是簡單的概念判斷題而是讓你寫出KL散度的定義式并解釋它在變分推斷里的作用。KL散度的定義式是KL(P || Q) Σ P(x) * log(P(x) / Q(x))注意KL散度不對稱KL(P||Q) ≠ KL(Q||P)所以它不是一個真正的距離度量。筆試選擇題經常挖這個坑。ELBO的推導其實是變分推斷的核心。我們想最大化證據 log P(X)但直接算很難因為要積分掉隱變量 Z。于是引入一個變分分布 q(Z)利用Jensen不等式得到log P(X) ≥ E_{q(Z)}[log P(X, Z) - log q(Z)]右邊的期望就是ELBO。它等于ELBO E_q[log P(X|Z)] - KL(q(Z) || P(Z))這個式子很有用最大化ELBO等價于在“擬合數據”和“逼近先驗”之間做權衡。筆試如果只考到一個層面你寫出ELBO的分解式并解釋“第一項是重建似然第二項是正則項”就足夠了。如果面試追問再往VAE上引。我當時復習的時候特意把KL散度、ELBO、EM算法串起來理解EM算法里E步就是在固定參數時計算隱變量的后驗分布本質上也和KL散度有關。把這些點串成一條線比零散背誦效率高很多。3.3 智能優化算法粒子群、模擬退火、遺傳算法熱搜詞里頻繁出現“粒子群算法原理”“模擬退火算法”這說明這類智能優化算法在算法崗筆試中的出鏡率不低。它們的定位是當問題規模大、或者目標函數不可導時傳統梯度方法失效需要借助啟發式搜索。粒子群算法PSO的核心是模擬鳥群覓食每個粒子有位置和速度更新時受兩個因素影響——個體歷史最優 pbest 和全局歷史最優 gbest。速度更新公式v_i w * v_i c1 * r1 * (pbest_i - x_i) c2 * r2 * (gbest - x_i) x_i x_i v_i這里 w 是慣性權重c1 是自我認知系數c2 是社會認知系數。筆試選擇題常考“w過大會怎樣”——答案是全局搜索能力強但收斂慢w過小則容易陷入局部最優。模擬退火算法的核心是Metropolis準則在退火過程中當新解更優時一定接受更差時以一定概率接受概率隨溫度降低而減小。概率公式是 exp(-ΔE / T)。這個“以一定概率接受差解”的設計目的是跳出局部最優和貪心算法“只接受更優解”的機制完全不同。這類題飛豬筆試一般不會讓你寫完整代碼而是放在選擇題中讓你判斷“這種做法體現了什么思想”。答這類題的關鍵不是死記步驟而是理解每種優化算法解決的核心問題。3.4 控制與信號類算法PID、卡爾曼濾波、FOC你可能會覺得奇怪算法崗筆試為什么會出現PID、卡爾曼濾波、FOC這些偏控制領域的算法。其實不少大廠算法崗也會涉及IoT設備、硬件數據、時序信號處理所以這些詞出現在熱搜里不是偶然。PID算法筆試考得最多的是增量式PID公式Δu(k) Kp * (e(k) - e(k-1)) Ki * e(k) Kd * (e(k) - 2e(k-1) e(k-2))筆試選擇題常問如果系統響應太慢應該增大哪個參數答案是增大Kp或適當增大Ki。如果系統超調嚴重、震蕩頻繁應該增大Kd來抑制變化。卡爾曼濾波則是狀態估計算法筆試高頻考點是“預測—更新”兩步套路預測x_pred F * x_prevP_pred F * P_prev * F^T Q更新K P_pred * H^T * (H * P_pred * H^T R)^(-1)x_new x_pred K * (z - H * x_pred)P_new (I - K * H) * P_pred不需要你把矩陣寫完但要能說清楚Q和R分別代表過程噪聲和觀測噪聲的不確定性K卡爾曼增益決定了更相信模型預測還是更相信傳感器觀測。如果R很小說明觀測噪聲小卡爾曼增益會偏大濾波器更信任觀測值。4. 實操過程從讀題到AC的完整復盤4.1 筆試環境與流程提前踩點更安心飛豬當時用的是常見的在線筆試平臺支持C、Java、Python等主流語言但要注意平臺不會幫你自動補全代碼也沒有本地IDE那么智能。很多人平時習慣用PyCharm或VSCode到了筆試平臺連個括號匹配提示都沒有寫起來特別別扭。我建議在正式筆試前至少花半天時間去熟悉平臺的代碼編輯器。具體來說試一下縮進是空格還是Tab、錯誤提示怎么看、有沒有“測試用例”按鈕、代碼是單文件提交還是多文件。我當時就吃過虧有一道題里要讀一行包含空格的字符串平臺自帶的輸入示例是用“\n”分隔的我一開始沒看清導致解析錯誤。另外要注意語言選擇。Python寫起來快但某些平臺對Python的支持比較“原始”遞歸層數會被限制如果趕上DFS或者遞歸DP的題很可能會爆棧。我當時遇到一道題第一反應是用遞歸做動態規劃寫完后本地通過平臺卻報“棧溢出”改成自底向上的遞推才過。這個細節值得提前知道。4.2 真題一手推KMP的next數組題目還原給定模式串 p abacaba寫出它的next數組并說明其中next[6]的含義。解題過程明確next數組定義next[i]表示p[0..i-1]的最長相等前后綴長度。逐項計算next[0]-1, next[1]0, next[2]0, next[3]1, next[4]0, next[5]1, next[6]0, next[7]3。next[6]的含義是當匹配到p[6]失敗時模式串應該回退到位置0因為next[6]0即從頭開始重新匹配。如果把 next[6]3則說明p[0..2]p[4..6]aba匹配失敗時可以跳到位置3保留已經匹配的“aba”前綴。這個答題思路在筆試里很占便宜不是只寫答案還寫清楚推導過程和含義面試官能一眼看出你是真懂還是背題。4.3 真題二帶權活動選擇動態規劃題目還原有 n 個活動每個活動有開始時間 s_i、結束時間 e_i 和收益 v_i選擇不沖突的活動求最大總收益。n ≤ 10^5時間范圍 0 ~ 10^9。這是一道典型的“加權區間調度”問題。貪心選結束時間最早只能保證數量最多不能保證收益最大。正確做法是按結束時間 e_i 升序排序。定義 dp[i] 為前 i 個活動能獲得的最大收益。轉移方程dp[i] max(dp[i-1], dp[p[i]] v_i)其中 p[i] 表示“最后一個結束時間 s_i”的活動編號。因為數組已按結束時間排序所以 p[i] 可以用二分查找在 O(log n) 時間內找到。核心代碼如下Pythonimport bisect # activities [(start, end, value)] activities.sort(keylambda x: x[1]) n len(activities) starts [a[0] for a in activities] ends [a[1] for a in activities] dp [0] * (n 1) for i in range(1, n 1): s, e, v activities[i-1] # 找到最后一個結束時間 s 的活動 j bisect.bisect_right(ends, s, 0, i - 1) dp[i] max(dp[i-1], dp[j] v) print(dp[n])這道題我當時的失誤是忘記給活動按結束時間排序就開始寫轉移方程寫到一半發現不對又回來改。所以強烈建議看到區間類DP第一步永遠是排序不是急著設狀態。4.4 真題三酒店價格預測的業務設計題題目還原如果你要為飛豬上一個“酒店未來30天價格預測”的功能你會怎么做要求給出技術方案、特征設計和評估指標。這類開放題沒有標準答案但答題框架很重要。我當時的回答思路是三層第一層問題拆解。酒店價格預測本質上是一個時間序列預測問題但又有特殊性——價格受節假日、供需關系、競對價格、用戶預訂行為影響不是簡單ARIMA能解決的。第二層方案選型。短中期預測可以用LightGBM/XGBoost把時間特征星期幾、是否節假日、距出行日天數、酒店特征星級、評分、歷史價格、市場特征周邊同等級酒店平均價格、搜索熱度作為特征輸入。如果需要捕捉長期依賴再上LSTM或Transformer但實際業務里樹模型往往性價比更高、更容易解釋。第三層評估指標。價格預測的誤差評估不能用單一指標。我當時寫的是整體用MAPE平均絕對百分比誤差但它對低價格酒店很不友好價格100元的酒店差50元和價格1000元的酒店差50元MAPE差異巨大。所以可以補充WAPE加權絕對百分比誤差或者分價格段評估。這道題其實考察的是“能不能把一個寬泛的問題轉化為可執行的算法方案”。平時如果只刷LeetCode遇到這種題容易手足無措。建議多積累幾個常用業務場景的算法方案比如推薦排序、價格預測、銷量預估、異常檢測。5. 常見問題與避坑技巧實錄5.1 時間不夠怎么辦優先級與取舍飛豬筆試的總時間是固定的但很多人在選擇題上花費過多時間導致編程題倉促收尾。我看到的普遍情況是選擇題里有幾道機器學習推導題比如KL散度的變形、梯度公式的推導容易讓人糾結。我的建議是把這類題控制在每題2分鐘內如果超過2分鐘還沒有思路先標記跳過去。合理的優先級是會做的編程題 會做的選擇題 會做一半的編程題 糾結的選擇題。編程題一道完整AC的分值往往頂好幾道選擇題所以哪怕放棄一兩道選擇題也要保證編程題有充分的調試時間。5.2 邊界條件與數據范圍最容易翻車的地方筆試翻車最常見的不是思路不會而是邊界條件沒處理。比如KMP的 next 數組很多人計算到中間就忘了 next[0] 的約定動態規劃的狀態數組往往會多開一位結果初始化寫錯二分查找的邊界條件更是重災區。我的經驗是寫完代碼后不要急著提交先用三組數據進行自測——最小輸入比如n1、極端輸入比如所有區間都重疊、隨機輸入。這大概多花3分鐘但能避免大量無謂的罰時。飛豬筆試平臺支持自測用例一定要用起來。還有一個容易被忽略的點數據范圍決定算法選型。如果 n ≤ 10^5O(n^2) 的算法基本會超時如果 n ≤ 20可以考慮狀態壓縮DP和搜索。做題前先看一眼數據范圍再決定寫哪種復雜度的算法這是基本功。5.3 “算法崗筆試是不是只看編程”的常見誤區不少準備秋招的人以為算法崗筆試就是刷題把精力全投在LeetCode上結果到了考場發現還有大量機器學習選擇題和場景設計題一下子就懵了。飛豬這場筆試就很典型編程題只占一部分還有不少選擇題在考概率統計、模型原理。我的建議是準備算法崗筆試要雙線并行一條線是數據結構與算法刷題重點突擊字符串、DP、圖論、貪心另一條線是機器學習基礎復盤手推邏輯回歸、K-Means、KNN、KL散度、集成學習這些高頻考點。尤其到了秋招后期大廠筆試越來越重視對算法原理的理解這是趨勢。5.4 刷題準備崗位匹配的復習路線結合飛豬的業務場景旅行推薦、價格預測、搜索排序、供需預測我給準備投飛豬算法崗的同學劃個復習重點必刷算法題字符串匹配KMP、區間DP、背包DP、最長上升子序列、TopK、Dijkstra、并查集。必會ML模型邏輯回歸、決策樹/隨機森林/GBDT/XGBoost、K-Means、KNN、樸素貝葉斯。必懂數學概念KL散度、極大似然估計、貝葉斯公式、期望/方差、正態分布。可以了解但不用死磕粒子群、模擬退火、遺傳算法等智能優化算法知道核心思想即可。有時間再擴展PID、卡爾曼濾波、FOC這些偏控制/信號的算法出現概率較低但一旦出現就是區分度很高的題。按這個路線準備既能覆蓋大部分考點又不至于陷入無意義的題海。飛豬筆試里那幾道讓我印象深刻的題事后復盤其實都在這條路線的覆蓋范圍內。如果你能把上述內容真正吃透就算題型換一換也基本能穩住。