
前幾天整理云盤里的舊資料翻出當年備戰(zhàn)微軟校招時整理的一套題目正是網(wǎng)上流傳很廣的2014年研發(fā)工程師筆試卷B。那段時間我把它來回做了三遍每一遍都能發(fā)現(xiàn)新的問題最后靠著這套題的復盤拿到了面試機會?,F(xiàn)在回頭看這套題雖然已經(jīng)過去快十年但它的考察思路和今天的算法面試依然高度一致非常適合正在準備大廠研發(fā)崗、或者想檢驗自己C/C和算法基本功的人當作自測材料。先說結論這套筆試卷B整體難度中等偏上不算變態(tài)但陷阱非常多。它不考任何框架、不考花哨的新技術核心就三塊——C/C語言細節(jié)、算法與數(shù)據(jù)結構基本功、快速編碼能力。如果你能拿75分以上面試輪是很有希望進的。下面我把這套題的題型結構、高頻考點和編程大題的完整解法拆開講順便把我踩過的坑也一并寫出來。1. 2014年微軟研發(fā)筆試卷B整體拆解與出題邏輯1.1 筆試卷的題型分布與考察維度我手頭這份回憶版B卷結構大概是這樣的選擇題約10道、填空題和簡答題2到3道、編程大題2道外加一道選做的附加題。總時長90分鐘到120分鐘卷面滿分100分左右。選擇題每題分值不高但勝在覆蓋面廣幾乎每道題都埋了1到2個坑簡答題主要考代碼理解和邏輯推導比如給你一段程序讓你寫出輸出結果編程大題則是整張卷子的重頭戲一道題動輒20到30分基本決定你能不能過線。從考察維度上看這張卷子其實很克制的。它不考操作系統(tǒng)源碼、不考編譯原理、不考網(wǎng)絡協(xié)議細節(jié)重心非常明確C/C語言細節(jié)指針、數(shù)組、結構體、虛函數(shù)、內(nèi)存布局大概占30%左右。算法與數(shù)據(jù)結構鏈表、字符串、排序、查找、遞歸大概占50%左右?;A系統(tǒng)概念進程線程、堆棧區(qū)別、動態(tài)鏈接之類的概念題占剩下的20%。這個比例你品一下就知道微軟當年的校招邏輯就是“算法定天下”。為什么這么設計后面細說。1.2 為什么微軟喜歡靠算法題篩人有人可能覺得微軟這種體量的公司筆試應該考系統(tǒng)設計、考業(yè)務場景其實恰恰相反。校招研發(fā)崗的筆試和社招完全不是一個路子。校招候選人沒有實際項目經(jīng)驗面試官能快速判斷的就是兩件事第一你的計算機基礎扎不扎實第二你的腦子轉得快不快、代碼能不能寫利索。算法題恰好同時滿足這兩個需求。一道反轉鏈表能看出你對指針和內(nèi)存的理解一道第K大元素能看出你的排序和分治功底。更重要的是算法題可以在兩個小時內(nèi)批量考察大量候選人成本低、信號強、很難靠背題蒙混過關。微軟面試中著名的“白板編程”文化從筆試階段就已經(jīng)開始鋪墊了。所以你看這套2014年筆試卷B它的出題邏輯其實很簡單用選擇題過濾那些基礎不牢的人再用編程大題留下真正能寫代碼的人。明白這個邏輯你就知道備考重點應該放在哪兒了——說白了就是兩板斧語言基礎吃透、算法題刷透。1.3 分數(shù)權重與時間分配策略這里直接給一份我用下來覺得最舒服的時間分配方案。假設總時長120分鐘題型建議用時策略選擇題20分鐘快速掃題不確定的先標記不戀戰(zhàn)簡答題15分鐘寫出關鍵點即可不要長篇大論編程大題60分鐘每題留足20-30分鐘先想思路再寫碼附加題15分鐘大題搞定了才碰拿不到不虧檢查10分鐘重點檢查邊界條件和數(shù)組越界我的個人習慣是拿到卷子先花兩分鐘通讀一遍不是逐字看而是掃一眼每道題大概在考什么心里有個數(shù)。尤其是編程大題我會先看題目描述和輸入輸出示例在腦子里初步構思一下解法然后再回頭做選擇填空。這樣等做到大題的時候思路其實已經(jīng)醞釀了一會兒落筆會順很多。2. 選擇題高頻考點深度解析2.1 C/C內(nèi)存與指針的基本功選擇題里幾乎每年必考的就是sizeof和指針之間的關系。我記得B卷里就有一道類似的題表面上看是一道普通的代碼輸出題實際上坑全在數(shù)組名退化上。void foo(int arr[]) { // arr 是函數(shù)參數(shù)本質(zhì)是一個指針 printf(%zu\n, sizeof(arr)); // 64位系統(tǒng)上輸出8 } int main() { int arr[10]; printf(%zu\n, sizeof(arr)); // 輸出40 printf(%zu\n, sizeof(arr) / sizeof(arr[0])); // 輸出10 foo(arr); // 輸出8 return 0; }這里有兩層坑。第一層很多人知道sizeof(arr)在main函數(shù)里是40因為數(shù)組名代表的是整個數(shù)組10個int乘以4字節(jié)。第二層坑在于數(shù)組作為函數(shù)參數(shù)傳遞時會退化為指向首元素的指針所有你以為是“傳數(shù)組”的寫法實際傳的都是指針。所以在foo里面sizeof(arr)返回的是指針的大小64位環(huán)境下就是8。類似的還有字符串相關的陷阱char *p hello; char arr[] hello; printf(%zu %zu\n, sizeof(p), sizeof(arr)); // 8 6 printf(%zu %zu\n, strlen(p), strlen(arr)); // 5 5sizeof(arr)是6因為數(shù)組版本會在末尾自動加一個\0sizeof(p)是8指針大小跟字符串長度無關而strlen永遠數(shù)到\0為止所以兩者都是5。這道題如果對字符串字面量的存儲機制不熟悉很容易把sizeof(p)誤寫成6。這類題考察的核心就一句話數(shù)組名、指針、字符串字面量這三者之間的區(qū)別。建議備考時把sizeof和strlen的對比、數(shù)組參數(shù)退化、字符數(shù)組和字符指針的區(qū)別這三個知識點反復吃透選擇題的C/C部分基本就能拿下大半。2.2 虛函數(shù)、虛表與運行時多態(tài)B卷里還有一道關于虛函數(shù)的題我記得類似這樣一個基類指針指向派生類對象調(diào)用一個虛函數(shù)和一個普通函數(shù)分別調(diào)用的是哪個版本。class Base { public: virtual void show() { printf(Base\n); } void normal() { printf(Base normal\n); } }; class Derived : public Base { public: void show() override { printf(Derived\n); } void normal() { printf(Derived normal\n); } }; int main() { Base *p new Derived(); p-show(); // 輸出 Derived p-normal(); // 輸出 Base normal delete p; }這道題對熟悉多態(tài)的人來說很簡單但當時有不少同學栽在第二行。原因就是沒有記清楚只有虛函數(shù)才具備動態(tài)綁定能力。p-show()運行時通過虛表找到Derived的版本輸出Derived而normal()沒有加virtual編譯階段就根據(jù)指針類型決定調(diào)用Base的版本。還有一個擴展考點是析構函數(shù)為什么要聲明為虛函數(shù)Base *p new Derived(); delete p; // 如果析構函數(shù)不是虛函數(shù)只會調(diào)用Base的析構可能造成內(nèi)存泄漏這也是微軟筆試面試中反復出現(xiàn)的細節(jié)題。本質(zhì)原因是delete一個基類指針時編譯器在編譯期只能看到指針的靜態(tài)類型不知道它到底指向的是哪個派生類對象。如果析構函數(shù)不是虛函數(shù)就不會觸發(fā)動態(tài)綁定Derived部分可能得不到正確釋放。應對這類題我建議你梳理一張“virtual機制”的腦圖虛函數(shù)如何實現(xiàn)動態(tài)綁定、虛表和虛指針的存在位置、構造函數(shù)不能是虛函數(shù)的原因、析構函數(shù)建議聲明為虛函數(shù)的原因。這幾點一旦理清相關選擇題無論怎么變形都不會被難住。2.3 數(shù)據(jù)結構復雜度數(shù)組、鏈表、哈希表怎么選有一類選擇題特別有意思題目會給出幾個常見操作問哪種數(shù)據(jù)結構效率最高。這類題本質(zhì)上是在考察對復雜度的理解而不是死記硬背結論。比如B卷里有道題要求在頻繁插入、刪除的場景下選擇合適的數(shù)據(jù)結構答案肯定是鏈表但你要能解釋為什么。操作數(shù)組鏈表哈希表隨機訪問O(1)O(n)O(1) 平均頭部插入O(n)O(1)不一定中間插入O(n)O(1)不適用按值查找O(n)O(n)O(1) 平均這里要特別注意“平均”兩個字。哈希表在有大量沖突時會退化最壞情況下查找是O(n)所以在對時延要求苛刻的場合不能無腦選哈希表。我記得那套卷子里有一道引申題問“如果哈希函數(shù)選得不好所有元素都映射到同一個桶里那查找復雜度是多少”正確答案是O(n)很多人會錯選O(1)。數(shù)組最大的優(yōu)勢是緩存局部性好實際運行速度往往比鏈表快這也是一個很多人忽略的點。筆試題目里如果只說“存儲一連串整數(shù)主要做順序遍歷”選數(shù)組通常比鏈表更合理因為內(nèi)存是連續(xù)的CPU緩存命中率遠高于鏈表。這個結論在紙上分析復雜度時看不到但微軟這種做產(chǎn)品的公司出題人心里是裝著實際工程的。2.4 位運算技巧兩行代碼解決一個經(jīng)典問題B卷里關于位運算的題不算難但很考驗“有沒有見過這類技巧”。比如判斷一個正整數(shù)是不是2的冪int isPowerOfTwo(int n) { return n 0 (n (n - 1)) 0; }原理很簡單一個數(shù)如果是2的冪它的二進制表示里只有一個1比如4是1008是1000。減去1以后原來1的位置變成0后面的位全部變成1。如果這個數(shù)原本只有一個1n (n - 1)的結果一定是0。如果原本有多個1結果是去掉最低位的1之后剩下的值不會是0。另一個經(jīng)典題是統(tǒng)計一個整數(shù)二進制表示里有多少個1int countOnes(int n) { int count 0; while (n) { n (n - 1); count; } return count; }這段代碼每次循環(huán)把最低位的1變成0循環(huán)次數(shù)等于1的個數(shù)而不是二進制位數(shù)。從負數(shù)到正數(shù)、從0到最大值都能正確統(tǒng)計。選擇題里問“對于整數(shù)256這個函數(shù)返回多少”答案是1如果對位運算不敏感很容易算成8或者其他數(shù)字。這類位運算技巧不建議死記代碼而是理解“減去1翻轉低位”這個規(guī)律考試時即使忘了具體實現(xiàn)也能現(xiàn)場推出來。平時準備的時候把移位、異或、與或非的常見套路整理到一起每天看一遍選擇題基本不會失分。3. 編程大題從思路到實現(xiàn)的完整代碼3.1 鏈表反轉迭代、遞歸和尾遞歸鏈表反轉是微軟筆試面試里出現(xiàn)頻率最高的題之一2014年這套B卷里我記得也有它的變體。它考察的點非常集中指針操作、邊界處理、循環(huán)或遞歸思維。題目一般長這樣給定一個單鏈表反轉后返回新的頭節(jié)點。迭代寫法是最容易理解的核心思路是遍歷過程中不斷翻轉當前節(jié)點的next方向struct ListNode { int val; struct ListNode *next; }; struct ListNode* reverseList(struct ListNode* head) { struct ListNode *prev NULL; struct ListNode *curr head; while (curr ! NULL) { struct ListNode *next curr-next; // 先保存下一個節(jié)點 curr-next prev; // 翻轉當前節(jié)點的指針 prev curr; // prev 前移 curr next; // curr 前移 } return prev; // prev 最后指向原鏈表的尾節(jié)點也就是新鏈表的頭 }這里最容易犯的錯誤是忘記在修改curr-next之前保存next。一旦先把指針翻轉了后面的節(jié)點就丟了。我當年第一次寫這個題就踩了這坑debug了半天所以在代碼注釋里也特別標出來了。遞歸寫法更精簡但理解門檻更高struct ListNode* reverseListRecursive(struct ListNode* head) { if (head NULL || head-next NULL) { return head; } struct ListNode *newHead reverseListRecursive(head-next); head-next-next head; // 讓下一個節(jié)點指回當前節(jié)點 head-next NULL; // 斷開原來的正向鏈接 return newHead; }遞歸思想是假設后面的部分已經(jīng)反轉好了當前只需要處理自己這個節(jié)點和下一個節(jié)點之間的關系。空間復雜度O(n)因為遞歸棧要用n層。筆試時兩種寫法都可以但要記得主動說明時間復雜度和空間復雜度。迭代是O(1)空間遞歸是O(n)空間面試官聽了會認為你對復雜度有清晰認知。變換形式還有一種“反轉鏈表前K個節(jié)點”或者“每K個一組反轉”難度會上去一檔但核心思想一樣只是多了一層分組和邊界處理。建議備考時把基礎反轉寫得滾瓜爛熟再嘗試變體會順手很多。3.2 字符串去重與原地操作字符串相關的編程大題在B卷里也有露面。我記得有一道題要求把字符串中重復的字符去掉只保留第一次出現(xiàn)的順序。比如輸入abcaabcd輸出abcd。最直接的想法是開一個新的字符串遍歷原串時判斷當前字符是否已經(jīng)出現(xiàn)過。這在C/C里可以用一個長度為128或256的int數(shù)組當哈希表void removeDuplicates(char *str) { if (str NULL) return; int hash[256] {0}; int writeIdx 0; for (int i 0; str[i] ! \0; i) { unsigned char ch (unsigned char)str[i]; if (!hash[ch]) { hash[ch] 1; str[writeIdx] str[i]; } } str[writeIdx] \0; }這里有兩個細節(jié)特別值得注意。第一字符強轉成unsigned char再作為數(shù)組下標是因為C語言標準里char不一定是有符號的直接用str[i]當下標如果字符是負數(shù)會訪問到hash[-1]這種越界區(qū)域程序直接崩潰。第二原地操作的意思是直接在原字符串上寫入把不重復的字符依次往前放最后在正確位置補一個\0。這道題的時間復雜度O(n)空間O(1)因為哈希表大小固定是256。筆試時如果要求“不允許用額外存儲空間”那可以用雙重循環(huán)O(n^2)的做法每次比較當前字符和前面已經(jīng)保留的字符但代碼會更繞。我的建議是先把哈希表版本寫對再根據(jù)題目限制作的放矢地調(diào)整。字符串題在微軟筆試題里占有不小的比重建議把常見的子串查找、回文判斷、字符計數(shù)、原地反轉、去重這幾類題目都練一遍就能覆蓋大部分場景。3.3 求第K大元素快速選擇算法求無序數(shù)組中第K大的元素是B卷編程大題里比較有分量的一道。很多人第一反應是先排序再索引復雜度O(n log n)但如果數(shù)組規(guī)模很大這個解法通常不是出題人想要的。更優(yōu)的方案是基于快速排序的partition思想也叫快速選擇Quick Select平均時間復雜度能到O(n)。求第K大可以轉換成求“第(n-K1)小”。這部分我當時用了Lomuto分區(qū)方案的寫法int partition(int arr[], int low, int high) { int pivot arr[high]; int i low; for (int j low; j high; j) { if (arr[j] pivot) { int temp arr[i]; arr[i] arr[j]; arr[j] temp; i; } } arr[high] arr[i]; arr[i] pivot; return i; } int quickSelect(int arr[], int low, int high, int k) { if (low high) return arr[low]; int pivotIndex partition(arr, low, high); int leftLen pivotIndex - low 1; if (leftLen k) { return arr[pivotIndex]; } else if (k leftLen) { return quickSelect(arr, low, pivotIndex - 1, k); } else { return quickSelect(arr, pivotIndex 1, high, k - leftLen); } }調(diào)用方式求第K大實際上是求第n - K 1小代入quickSelect(arr, 0, n - 1, n - K 1)??焖龠x擇的平均時間復雜度是O(n)因為每次partition之后只需要處理一邊的數(shù)據(jù)規(guī)模是按比例縮小的。但它有一個軟肋如果pivot每次都選得很差比如在近乎有序的數(shù)組里固定取最后一個元素作為pivot最壞情況時間復雜度會退化為O(n^2)。筆試時如果輸入規(guī)模很大建議對數(shù)組做一次隨機打亂或者在partition時隨機選pivot能有效降低退化概率。這道題還有一種解法是用大小為K的最小堆時間復雜度O(n log K)。如果K值很小比如“找第2大的數(shù)”堆方案在某些場景下更穩(wěn)定。我當時在卷子上寫的是快速選擇因為它空間復雜度O(1)不算遞歸棧而且代碼量少適合筆試這種時間緊張的場合。3.4 附加題全排列的非遞歸生成B卷的附加題里有一道生成全排列的題輸入一個字符串輸出它的所有排列。最經(jīng)典的解法是遞歸回溯思路是固定第一個字符然后遞歸排列后面的部分void swap(char *a, char *b) { char temp *a; *a *b; *b temp; } void permute(char *str, int start, int end) { if (start end) { printf(%s\n, str); return; } for (int i start; i end; i) { swap(str[start], str[i]); permute(str, start 1, end); swap(str[start], str[i]); // 恢復現(xiàn)場 } }需要注意“恢復現(xiàn)場”這一步。如果不把交換過的字符換回去遞歸返回時字符串順序已經(jīng)被打亂后面的排列就會出現(xiàn)嚴重的重復或者遺漏。這個細節(jié)幾乎是全排列題的高頻bug點。如果題目要求去重比如輸入aab就要在循環(huán)里加一個條件如果某個字符在當前位置已經(jīng)出現(xiàn)過就跳過。可以用一個長度為256的數(shù)組標記當前位置是否已經(jīng)使用過某個字符void permuteUnique(char *str, int start, int end) { if (start end) { printf(%s\n, str); return; } int used[256] {0}; for (int i start; i end; i) { unsigned char ch (unsigned char)str[i]; if (used[ch]) continue; used[ch] 1; swap(str[start], str[i]); permuteUnique(str, start 1, end); swap(str[start], str[i]); } }非遞歸的做法是基于字典序的next_permutation思路是從右往左找到第一對相鄰的升序對再從右往左找到第一個大于左側元素的值交換后反轉右側序列。這個算法的手寫實現(xiàn)比遞歸版復雜不少但好在C的STL頭文件里已經(jīng)提供了std::next_permutation。筆試時如果時間緊張直接用STL是合理選擇但前提是你得清楚它的底層層邏輯不然面試官追問起來會比較麻煩。4. 筆試實操經(jīng)驗與環(huán)境避坑4.1 筆試前的開發(fā)環(huán)境準備筆試之前有一個非常實際的坑就是開發(fā)環(huán)境的準備。當年的問卷一般會給兩個選擇一是直接在網(wǎng)頁上寫代碼二是本地寫完后提交。很多人習慣用Visual Studio那就要提前確認編譯器和運行庫是否齊全。我當年第一次模擬練習時本地VS報了一堆鏈接錯誤折騰半天才發(fā)現(xiàn)是運行庫版本不匹配白白浪費了半小時心態(tài)都有點崩。后來我養(yǎng)成了一個習慣除了自己常用的IDE還會用一個輕量級的編譯方式兜底。比如裝好MinGW或者GCC之后在命令行里執(zhí)行gcc -stdc99 -Wall -Wextra -o solution solution.c-Wall和-Wextra會打開大部分警告這對檢查數(shù)組越界、未初始化變量、類型轉換等問題非常有幫助。筆試現(xiàn)場如果編譯器提示warning很多時候不是語言本身有問題而是代碼里藏著隱患所以開著警告編譯是一個好習慣。如果你參加的是允許使用本地環(huán)境的筆試建議把所有模板代碼提前準備好鏈表節(jié)點定義、樹的節(jié)點定義、快排、歸并、二分查找、堆排序。這些基礎模板塊能夠幫你省下大量現(xiàn)場打字時間。注意模板不是讓你照抄答案而是減少重復敲結構體的時間把精力留給核心算法邏輯。4.2 時間分配與做題順序做題順序這件事我見過太多人栽跟頭。有些人拿到卷子就從第一題開始做選擇題做得很嗨結果到了最后一道編程大題只剩15分鐘手忙腳亂代碼都沒寫完。這是最典型的失誤。我的策略是大題優(yōu)先。拿到卷子先花兩分鐘通讀一遍確定編程大題的題號然后直接從大題開始寫。原因很簡單大題分值高、區(qū)分度大而且做完大題之后心態(tài)會踏實很多回頭再做選擇題就算有幾道拿不準也不會太慌。具體時間分配可以這樣參考環(huán)節(jié)時間說明通讀全卷2-3分鐘標記不確定的題目編程大題120-25分鐘先想清楚再寫不急著敲鍵盤編程大題220-25分鐘注意邊界條件附加題0-15分鐘如果大題順利可以嘗試選擇題填空20-25分鐘逐個擊破不確定的做個標記檢查5-10分鐘重點檢查數(shù)組越界、空指針、返回值這套流程我后來推薦給好幾個學弟學妹反映都還不錯。核心邏輯就一條用你的最佳狀態(tài)去打最能拉開分差的仗而不是把黃金時間浪費在低價值的題目上。4.3 面試官眼里的“好答案”長什么樣筆試雖然只看最終提交但微軟的筆試結果會和后續(xù)面試聯(lián)動。你在筆試編程題里暴露出的編碼習慣、邊界處理意識和解題思路往往會成為面試官提問的素材。所以從筆試開始就要有意識地培養(yǎng)“面試官友好型”的答題習慣。第一先寫思路再寫代碼。這不需要提交給閱卷系統(tǒng)但如果你在草稿紙上先畫一畫思路、列出時間復雜度和空間復雜度你的代碼質(zhì)量會明顯更高。我在做鏈表反轉時會先在草稿紙上畫三個節(jié)點模擬一下指針的移動過程這能避免“自以為寫對了但實際邏輯混亂”的情況。第二主動處理邊界條件??罩羔?、空數(shù)組、只有一個元素、全是相同元素這些情況每一道題都要問自己一遍。很多人提交的代碼在正常用例下AC一旦輸入為空或者長度為1就直接崩潰這在閱卷時是致命的。多寫幾行防御性代碼比如if (head NULL || head-next NULL) { return head; }不僅能防止崩潰還能讓閱卷人一眼看出你對邊界條件的敏感度。第三代碼風格要干凈。不要追求一行代碼寫三件事不要用a、b、c這種毫無意義的變量名。微軟的工程師文化比較看重可讀性和可維護性變量命名、縮進、注釋習慣都會被潛移默化地評估。筆試不是競賽不是寫越短的代碼越好而是寫的越清楚越好。5. 常見問題與高效備考路線5.1 我踩過的一些坑備考過程中我踩過的坑不算少挑幾個典型的講給后來的朋友聽希望你們少走彎路。第一個坑是只刷題不總結。我一開始用在線題庫刷題一晚上刷十幾道當時感覺效率極高。但隔一周再做同樣的題居然又要重頭開始推思路。后來我改了一種方式每道題做完之后在筆記本上寫三句話——這道題考察什么知識點、我的第一反應是什么、最優(yōu)解是什么。這樣刷題的數(shù)量降下來但鞏固率大幅提升。第二個坑是忽視手寫代碼。筆試雖然不一定要求手寫但面試經(jīng)常要白板編程。我最初習慣在IDE里寫代碼因為語法高亮、自動補全、即時編譯都幫我掩蓋了很多問題。等到白板上寫代碼時才發(fā)現(xiàn)連for循環(huán)的括號都不容易寫對更別提處理那些需要臨時變量交換的邏輯了。建議備考后期每天至少手寫兩三道題的完整代碼不要借助任何IDE輔助。第三個坑是忽略了編譯環(huán)境的細節(jié)。有一次我提交的代碼在本地跑得好好的結果到在線評測系統(tǒng)上直接編譯失敗原因是用了非C標準庫函數(shù)而評測環(huán)境的編譯參數(shù)比本地嚴格很多。從那以后我每次寫完代碼都會在命令行用嚴格的編譯參數(shù)跑一遍比如加-Wall -Werror。-Werror會把警告當成錯誤強迫我消除所有隱患。5.2 從一個月倒計時開始的刷題計劃如果你還有一個月就要參加類似性質(zhì)的筆試我建議把備考規(guī)劃成四個階段每周一個主題節(jié)奏相對舒服第一周語言基礎補漏。重點復習指針、數(shù)組、內(nèi)存布局、C的類/析構/虛函數(shù)。每天找?guī)椎勒Z言細節(jié)選擇題練手不急著刷算法題先把地基打穩(wěn)。第二周數(shù)據(jù)結構專項。鏈表、字符串、棧、隊列、二叉樹、哈希表每種結構至少刷10道題。務必把反轉鏈表、判斷回文、二叉樹遍歷這幾類基礎題練到閉眼能寫。第三周算法專項。排序、二分、雙指針、遞歸回溯、動態(tài)規(guī)劃。重點放在高頻題型上比如快速排序、歸并排序、第K大元素、最長公共子串等。第四周模擬考試。找一套往年的筆試題或在線題庫的模擬卷設定120分鐘鬧鐘在完全模擬筆試的環(huán)境下做完整套題。做完之后認真復盤每一道題尤其是錯題多問自己“為什么是這個答案”。輔助資料方面我強烈推薦《編程之美》這本書本身就是微軟研究院出的面試題集各種題目的思路非常貼近微軟的考察風格。另外《C和指針》是補C語言短板的利器雖然覆蓋面廣但隨便挑幾章看就能受益匪淺。如果算法底子比較薄可以配合《算法圖解》入門再逐步過渡到《算法導論》的相關章節(jié)。我個人在實際操作中的一個體會是刷題不要貪多貪多嚼不爛。同一個知識點比如鏈表反轉把這一個點吃透比草草刷十道不同類型的題更有價值。筆試考的不是你知道多少種算法而是在有限時間里把最經(jīng)典的解法寫得又快又準。最后再分享一個小技巧筆試前一周每天早起花10分鐘默寫一份“必備代碼清單”。我當時的清單是鏈表反轉、快速排序、歸并排序、二分查找、二叉樹前中后序遍歷、層序遍歷、快速選擇、全排列遞歸版。每天寫一遍堅持一周等到真正上考場手里有糧心里不慌。這套2014年的筆試卷B雖然年代有點久遠但它的考點和經(jīng)典題目對今天的大廠校招依然很有參考價值希望這篇復盤能幫到你。