筆試卷全解析:從基礎(chǔ)考點到備考策略)
2014年騰訊研發(fā)筆試卷在很多老開發(fā)眼里就是一面照妖鏡。那年頭的筆試不像現(xiàn)在這樣海量刷題、系統(tǒng)設(shè)計滿天飛它考察的東西非?!霸肌盋語言、數(shù)據(jù)結(jié)構(gòu)、操作系統(tǒng)、網(wǎng)絡(luò)基礎(chǔ)外加幾道讓人拍桌子的智力題。我到現(xiàn)在還留著當(dāng)時考完的筆記回頭翻看發(fā)現(xiàn)這份試卷的價值其實遠(yuǎn)不止“找份工作”那么簡單——它像一次對計算機基礎(chǔ)功底的全面體檢哪些地方是半吊子哪些地方是真吃透了一張卷子就能試出來。這篇文章我想從命題思路開始把2014年騰訊研發(fā)筆試卷的考察要點、典型題型、解題邏輯以及我當(dāng)時踩過的坑完整拆一遍。無論你是準(zhǔn)備面試的應(yīng)屆生還是想借一份老卷子檢驗自己基礎(chǔ)的職場人都能從中找到能直接用的復(fù)習(xí)路徑和實操方法。1. 2014年騰訊研發(fā)筆試卷的考察版圖與命題邏輯1.1 整張卷子的模塊分布和題目類型2014年騰訊校招研發(fā)崗筆試卷整體結(jié)構(gòu)通常分為客觀題和主觀題兩大塊??陀^題以單選題為主也有少量多選題覆蓋的面非常寬包括C/C語法細(xì)節(jié)、數(shù)據(jù)結(jié)構(gòu)與算法復(fù)雜度、操作系統(tǒng)原理、計算機網(wǎng)絡(luò)基礎(chǔ)、數(shù)據(jù)庫基礎(chǔ)偶爾還會摻幾道Linux命令和概率統(tǒng)計。主觀題一般有兩到三道常見組合是手寫代碼題加算法設(shè)計題有時還配一道SQL題或系統(tǒng)設(shè)計小題。從考察比重來看C/C和數(shù)據(jù)結(jié)構(gòu)是絕對的核心兩項加起來差不多能占60%以上。操作系統(tǒng)和網(wǎng)絡(luò)各占10%到15%剩下的就是智力題、概率題和邏輯題。這種比例不是隨手定的它反映的是騰訊那個年代對研發(fā)崗位的真實期待你進(jìn)來之后要能看懂現(xiàn)有代碼要能寫底層模塊要能在線上問題出現(xiàn)時快速定位到底是內(nèi)存問題、線程問題還是網(wǎng)絡(luò)問題。所以基礎(chǔ)不牢的人試卷上非常容易暴露。1.2 為什么這個年代會這樣出題現(xiàn)在回頭看2014年的考題風(fēng)格會發(fā)現(xiàn)它和當(dāng)時的技術(shù)土壤有很強的關(guān)系。那時候騰訊的很多核心服務(wù)還是C寫的客戶端、后臺服務(wù)、游戲引擎C幾乎是無處不在。這意味著面試官需要招進(jìn)來的人立刻能上手維護(hù)現(xiàn)有代碼所以筆試?yán)锎罅靠疾熘羔?、?nèi)存、虛函數(shù)、STL這些C底層概念邏輯上非常順。另一個背景是移動互聯(lián)網(wǎng)剛進(jìn)入爆發(fā)期團(tuán)隊規(guī)模擴(kuò)張很快面試官手里簡歷堆積如山。筆試作為第一道篩選關(guān)卡必須做到“區(qū)分度大、作弊成本高、機器判斷快”。因此選擇題占了很大比例主觀題也以寫代碼為主目的就是快速判斷一個人基本功是否扎實有沒有真實編碼經(jīng)驗。理解了這個背景你就明白為什么這份試卷如此“硬核”——它不是考你懂多少新框架而是考你底子是否夠厚。2. 重點題型拆解數(shù)據(jù)結(jié)構(gòu)與算法題2.1 鏈表、棧與隊列類題目的經(jīng)典套路2014年這份試卷里鏈表的出鏡率非常高。我記得有類經(jīng)典題目比如判斷鏈表是否有環(huán)、找到環(huán)的入口節(jié)點、反轉(zhuǎn)鏈表、合并兩個有序鏈表。這些題目放在今天依然是面試高頻題區(qū)別在于當(dāng)年沒有 LeetCode 這種刷題平臺大家都是靠《算法導(dǎo)論》和《數(shù)據(jù)結(jié)構(gòu)》教材硬啃拿到題目先在紙上畫圖再一步步推導(dǎo)。以判斷鏈表是否有環(huán)這道題為例常規(guī)解法是快慢指針。慢指針每次走一步快指針每次走兩步如果鏈表中存在環(huán)快指針最終一定會追上慢指針。很多人會背這個結(jié)論但筆試題目如果稍微變一下比如要求你證明為什么快指針每次走兩步一定能追上很多人就卡住了。這里的關(guān)鍵在于當(dāng)慢指針進(jìn)入環(huán)時快指針一定已經(jīng)在環(huán)內(nèi)二者之間的相對速度差是1步因此距離會不斷縮短最終必然相遇。如果快指針每次走三步或四步反而不一定能保證追上因為可能出現(xiàn)循環(huán)跳過的情況。// 判斷鏈表是否有環(huán) bool hasCycle(ListNode *head) { ListNode *slow head; ListNode *fast head; while (fast ! NULL fast-next ! NULL) { slow slow-next; fast fast-next-next; if (slow fast) { return true; } } return false; }我當(dāng)時做題的心得是鏈表類題目必須做到“畫圖推演先于寫代碼”。因為鏈表操作最怕丟指針比如反轉(zhuǎn)鏈表時如果順序記錯很容易出現(xiàn)斷鏈或死循環(huán)。我的習(xí)慣是先畫出每一步的指針變化標(biāo)清楚哪根指針指向哪個節(jié)點再落筆寫代碼這樣寫出來的代碼基本一遍過。這個習(xí)慣后來在工作中排查鏈表相關(guān)問題也幫了大忙。2.2 排序與查找性價比最高的拿分區(qū)排序算法這塊2014年筆試卷幾乎必考。常見的出題方式有給一組數(shù)據(jù)問用快速排序第一趟劃分后的序列是什么比較不同排序算法在最好、最壞、平均情況下的時間復(fù)雜度或者要求手寫堆排序。對備考的人來說排序算法是性價比最高的拿分點因為規(guī)律性強、套路固定只要背熟幾種核心排序的實現(xiàn)過程選擇題很快就能拿下??焖倥判虻谝惶藙澐诌@類題考察的是對partition過程的理解。比如給定數(shù)組 5, 3, 8, 6, 2, 7, 1, 4以第一個元素5為基準(zhǔn)一趟劃分后數(shù)組會變成什么樣基準(zhǔn)元素最終落在哪個位置。這個問題需要你手動模擬雙指針交換的過程從右往左找比基準(zhǔn)小的從左往右找比基準(zhǔn)大的兩者交換直到指針重合。手動模擬一兩次不僅選擇題能答對手寫快排的代碼也會順手很多。還有一個容易被忽略的點是穩(wěn)定性??焖倥判?、堆排序、選擇排序都是不穩(wěn)定的插入排序、冒泡排序、歸并排序是穩(wěn)定的。2014年的卷子里這種題通常不會直接問你“哪種排序穩(wěn)定”而是藏在具體場景里比如“按成績降序排列成績相同按學(xué)號升序問應(yīng)該用什么排序”其實就是在考你對穩(wěn)定性的理解。我當(dāng)時就是因為沒注意到穩(wěn)定性這個細(xì)節(jié)白丟了一道不該丟的選擇題。2.3 動態(tài)規(guī)劃與遞歸拉分題出沒之處主觀題里最拉分的往往是動態(tài)規(guī)劃。騰訊2014年筆試卷出現(xiàn)過類似“編輯距離”“最長公共子序列”這類經(jīng)典DP問題也有更實際的場景題比如“給定一個整數(shù)數(shù)組找一個連續(xù)子數(shù)組使得其和最大”也就是最大子序和問題。這類題目考察的不只是你是否知道DP模板還有你把實際問題抽象成狀態(tài)轉(zhuǎn)移方程的能力。拿最大子序和來說第一步是定義狀態(tài)dp[i]表示以第i個元素結(jié)尾的連續(xù)子數(shù)組的最大和。狀態(tài)轉(zhuǎn)移方程是dp[i] max(nums[i], dp[i-1] nums[i])意思是要么從當(dāng)前元素重新開始要么把當(dāng)前元素接到前面的最優(yōu)子數(shù)組后面。理解了狀態(tài)定義代碼非常短def maxSubArray(nums): cur 0 max_sum nums[0] for num in nums: cur max(num, cur num) max_sum max(max_sum, cur) return max_sum這道題實際上有更簡單的貪心思路但DP理解到位后可以舉一反三處理很多變體題目。我當(dāng)時復(fù)習(xí)DP時的經(jīng)驗是不要急著刷大量題先過一遍常見DP模型包括背包、LIS、LCS、編輯距離、區(qū)間DP把每個模型的狀態(tài)定義和轉(zhuǎn)移方程手寫推導(dǎo)一遍再去做題。因為筆試卷子時間有限考場上現(xiàn)推狀態(tài)方程容易慌提前把這些基礎(chǔ)模型吃透臨場會穩(wěn)很多。3. C/C與操作系統(tǒng)筆試?yán)锏摹盎A(chǔ)盤”3.1 數(shù)組與指針C語言陣營的送命題2014年的筆試卷里C/C考點里最經(jīng)典的就是數(shù)組與指針的區(qū)別再配合sizeof運算符出題。這類題看起來簡單但失分率出奇地高因為容易混淆數(shù)組名、指針變量、指針數(shù)組和數(shù)組指針這幾個概念。舉個例子char str[] hellocharp hello問sizeof(str)和sizeof(p)分別是多少。前者是在棧上分配的字符數(shù)組包含了結(jié)尾的\0所以sizeof結(jié)果是6后者是一個指針變量在32位系統(tǒng)上是4在64位系統(tǒng)上是8。這道題的坑在于很多人默認(rèn)“字符串就是char”忽略了數(shù)組和指針在類型系統(tǒng)里的本質(zhì)區(qū)別。這些題考察的是對語言底層的實際理解程度不是背答案就能搞定的。另一個高頻考點是指針運算。比如int a[5] {1, 2, 3, 4, 5}; intptr (int)(a 1); 問(ptr - 1)是多少。這里的核心是a是一個指向整個數(shù)組的指針類型是int()[5]加1后指向數(shù)組a末尾的下一個位置也就是跨過了5個int再減1回退一個int指向5。做這類題必須搞清楚指針的“步長”也就是指針指向的類型有多大否則極易出錯。3.2 內(nèi)存管理與進(jìn)程線程的必考細(xì)節(jié)操作系統(tǒng)這個模塊2014年騰訊筆試基本圍繞內(nèi)存管理、進(jìn)程與線程的區(qū)別、死鎖條件和調(diào)度算法來出題。內(nèi)存管理里常見的有虛擬內(nèi)存、分頁分段、頁面置換算法。有一道題我記得很清楚給定一段訪問序列分別用FIFO和LRU算法計算缺頁次數(shù)。這種題就是送分題只要在草稿紙上畫好頁面框的狀態(tài)變化一步步推就能算對。不過要提防變體題。同樣是頁面置換如果把物理頁面框數(shù)提高缺頁次數(shù)反而增加的場景那就是Belady異常只有FIFO算法才會出現(xiàn)LRU不存在這個問題。題目如果這樣出其實是在考察你對算法特性的深入理解不是單純的計算。進(jìn)程與線程的區(qū)別幾乎是必考出題方式往往是“以下關(guān)于進(jìn)程和線程的描述正確的是”。考到的點通常是進(jìn)程是資源分配的基本單位線程是CPU調(diào)度的基本單位同一進(jìn)程的線程共享地址空間和資源但進(jìn)程之間互相隔離線程切換比進(jìn)程切換開銷小。死鎖方面則經(jīng)常會考死鎖的四個必要條件或者用資源分配圖判斷是否有可能進(jìn)入死鎖。3.3 計算機網(wǎng)絡(luò)TCP/IP的核心考點網(wǎng)絡(luò)模塊的考察也相當(dāng)集中。TCP三次握手、四次揮手、TIME_WAIT狀態(tài)、TCP與UDP的區(qū)別幾乎每年都會換著花樣出現(xiàn)。2014年筆試卷里有一道印象很深的題為什么TCP斷開連接需要四次揮手為什么TIME_WAIT狀態(tài)要等待2MSL這兩個問題其實都指向同一個本質(zhì)——TCP必須確保所有報文都能被可靠送達(dá)。我來解釋一下四次揮手的原因。TCP是全雙工通道斷開時兩個方向都要單獨關(guān)閉。主機關(guān)閉發(fā)送方向時只能說明它不再發(fā)數(shù)據(jù)但接收方向還開著對方仍然可能繼續(xù)發(fā)數(shù)據(jù)過來。所以每個方向都需要一次FIN和一次ACK加起來就是四次。TIME_WAIT等待2MSL的核心目的有兩個一是保證最后的ACK如果丟失對方重傳FIN時還能收到二是防止本連接已失效的報文出現(xiàn)在新連接中。理解了這兩個原因遇到選擇題變體也不怕。還有一個高頻考點是IP地址與子網(wǎng)掩碼計算。給定一個IP和一個子網(wǎng)掩碼要求計算網(wǎng)絡(luò)號、廣播地址或者判斷兩個IP是否在同一子網(wǎng)。這類題只要把二進(jìn)制換算做熟基本沒有難度。我的建議是考試時用最快的方式先把掩碼的非255部分換成二進(jìn)制然后對IP對應(yīng)位做與運算。4. 智力題與邏輯題思路比答案重要4.1 典型邏輯題的命題原型騰訊的筆試一直喜歡放智力題2014年也不例外。這類題往往和算法沒直接關(guān)系但考察的是邏輯推理和建模能力。常見的有燒繩子計時、假幣找次品、倒水問題、天平稱重以及一些概率題。我印象最深的是“1000瓶藥水中有1瓶有毒用多少只小白鼠能在24小時內(nèi)找出毒藥”這個問題。這實際上是一個二進(jìn)制編碼問題每只小白鼠的生死結(jié)果只有兩種狀態(tài)——活著或死亡對應(yīng)二進(jìn)制的0和1。n只小白鼠可以表示2的n次方種狀態(tài)999瓶毒藥需要至少10只小白鼠因為2的9次方是512不夠1000。解答的思路是把所有瓶子編號成二進(jìn)制再給每只小白鼠喂對應(yīng)二進(jìn)制位為1的瓶子的混合藥水最后根據(jù)死亡小鼠的組合來確定編號。這種題的考察點不在毒藥而在你有沒有能力把現(xiàn)實問題抽象成信息編碼問題。平時不接觸這類題的人考場上容易陷入“一只只試”的誤區(qū)而不是從信息量的角度考慮。4.2 解題策略如何在時間壓力下拆題智力題的答題策略和代碼題完全不同。代碼題有明確的演算路徑智力題的關(guān)鍵是快速識別它背后的數(shù)學(xué)模型。我的實戰(zhàn)經(jīng)驗是三步走。第一步先判斷這是哪一類模型的問題是編碼類、稱重類、還是概率類。第二步嘗試用最小規(guī)模的例子做模擬因為小規(guī)模情況比較容易找到規(guī)律比如n2、n3時結(jié)果是什么再推廣到n100。第三步在草稿紙上畫狀態(tài)圖或?qū)戇f推公式不要只用頭腦空想。這里必須強調(diào)一個考場上的應(yīng)變原則如果一道智力題卡了5分鐘還沒有清晰思路果斷先跳過做后面的題。因為智力題往往只有一道或者兩道分值占比并不高但會占用大量時間如果因為一道智力題導(dǎo)致算法題做不完就非常虧了。5. 筆試實戰(zhàn)復(fù)盤時間分配與踩坑清單5.1 120分鐘/180分鐘的答題時間策略2014年騰訊研發(fā)筆試通常給的時間是120分鐘到180分鐘。客觀題量大、知識點碎主觀題需要較長時間推演和寫碼所以時間分配一定要提前規(guī)劃好。我當(dāng)時的策略是客觀題控制在60到70分鐘內(nèi)完成不能超過這個時間因為主觀題至少要留出60分鐘。具體到每一道選擇題一般要求1到2分鐘內(nèi)給出答案。如果一道題做了3分鐘還沒出來說明這道題要么有陷阱某個知識點沒掌握要么是計算量特別大的題。我的做法是先在卷子上標(biāo)記一下跳過做后面的等把有把握的題全部做完再回頭處理這些標(biāo)記題。實際考下來回頭再看不一定能做對但不會因為死磕一道題導(dǎo)致后面大片題目空白。主觀題的時間分配也很有講究。第一道手寫代碼題通常是鏈表、二叉樹、或簡單DP這類題在15到25分鐘內(nèi)完成比較合理。第二道算法設(shè)計題則建議留至少30分鐘因為它需要讀題、建模、推導(dǎo)復(fù)雜度、寫代碼、檢查邊界少一步都容易翻車。如果還有SQL題或系統(tǒng)設(shè)計題安排在最后10分鐘到15分鐘解決。5.2 我見到的常見失分點復(fù)盤2014年那次考試以及后來帶新人的經(jīng)驗我總結(jié)出幾個高頻失分點給大家提個醒。第一個失分點是代碼題沒考慮邊界條件。比如反轉(zhuǎn)鏈表時很多人寫完了常規(guī)情況但入?yún)⑹强真湵砘蛑挥幸粋€節(jié)點時直接崩潰。建議寫完代碼后用至少三組輸入來測試空輸入、單元素輸入、正常規(guī)模輸入有條件還可以測一下超大輸入或溢出情況這些習(xí)慣能救回不少分。第二個失分點是“知道了大概思路就寫代碼”。很多人在紙上寫代碼時邏輯沒理順就開始動手寫一半發(fā)現(xiàn)狀態(tài)變量漏了或者循環(huán)條件反了只能涂涂改改卷面很難看。吃虧之后我養(yǎng)成了一個習(xí)慣動筆前先用兩三行注釋把核心思路寫出來比如“用快慢指針快指針先走k步再同步前進(jìn)”然后再寫代碼。第三個失分點是不重視復(fù)雜度分析。筆試卷子上要求寫代碼的題目往往還會要求分析時間復(fù)雜度和空間復(fù)雜度這個分值不能白丟。不管題目有沒有明確要求都主動寫上復(fù)雜度分析會顯得你考慮問題更完整。當(dāng)然前提是在代碼注釋或結(jié)尾處補充說明語言盡量簡潔清晰。6. 從2014到現(xiàn)在的筆試演進(jìn)與備考建議6.1 大廠筆試風(fēng)格的變化現(xiàn)在的大廠筆試和2014年相比已經(jīng)發(fā)生了很多變化。騰訊現(xiàn)在的研發(fā)筆試更側(cè)重于算法題通常在線編程平臺進(jìn)行題型以LeetCode風(fēng)格的題目為主考察范圍從數(shù)組、鏈表、二叉樹擴(kuò)展到動態(tài)規(guī)劃、貪心、DFS/BFS、并查集等。操作系統(tǒng)、網(wǎng)絡(luò)、C語法死記硬背的內(nèi)容在筆試?yán)锎蠓鶞p少轉(zhuǎn)而出現(xiàn)在面試環(huán)節(jié)的問答里。但這并不意味著當(dāng)年的筆試卷沒有參考價值。相反2014年騰訊筆試卷恰好暴露了基本功的各種細(xì)節(jié)這些細(xì)節(jié)在今天依然有很強的現(xiàn)實意義。比如對指針的理解、對內(nèi)存布局的認(rèn)識、對TCP協(xié)議狀態(tài)的把握在排查線上問題時依然用得上。筆試形式變了內(nèi)核并沒有變大廠依然在尋找基礎(chǔ)扎實、邏輯清晰、寫代碼嚴(yán)謹(jǐn)?shù)墓こ處煛?.2 給現(xiàn)役求職者的復(fù)習(xí)建議如果是準(zhǔn)備現(xiàn)在的校招或者社招我不建議直接否定老卷子。我的做法是“新舊結(jié)合”用2014年這份筆試卷來補基礎(chǔ)短板用LeetCode來提升代碼手感兩者并不矛盾。具體復(fù)習(xí)路徑上第一優(yōu)先級是算法題建議每天至少保持1到2道高質(zhì)量題目的訓(xùn)練量以中等難度為主輔以少量困難題。每道題都要做到能講清楚思路、能分析復(fù)雜度、能寫出無bug的代碼。第二優(yōu)先級是計算機基礎(chǔ)操作系統(tǒng)、網(wǎng)絡(luò)、數(shù)據(jù)庫這三門課過一遍核心知識點即可重點放在高頻考點上。第三優(yōu)先級是項目復(fù)盤準(zhǔn)備2到3個自己真正做過、能講清楚技術(shù)細(xì)節(jié)的項目因為筆試通過后后面的面試幾乎每輪都會追問項目。別忘了留出一周時間專門做模擬筆試。很多人平時刷題寫得挺好一到限定時間的在線筆試就容易慌因為不習(xí)慣看倒計時、對著純文本框?qū)懘a。提前用平臺模擬幾次能把這種陌生感降下來考場上發(fā)揮也會穩(wěn)定很多。我當(dāng)年就是因為沒提前模擬第一場筆試差點沒寫完后來學(xué)聰明了每次都會拿往年題做全真模擬。這套復(fù)習(xí)思路其實和2014年備考的核心邏輯一脈相承你要做的不是背題而是把每一個基礎(chǔ)知識點真正吃透。老卷子給我的最大啟發(fā)也在這里——那些看起來“偏基礎(chǔ)”的題目放到現(xiàn)在的技術(shù)環(huán)境里依然是評判一個工程師能不能走遠(yuǎn)的重要標(biāo)準(zhǔn)。