盤:基礎(chǔ)扎實(shí)是關(guān)鍵,手寫題與滑動(dòng)窗口經(jīng)驗(yàn)分享)
每年秋招的節(jié)奏都像打仗小米這輪前端崗筆試我是在九月中旬收到的通知。說實(shí)話看到“第二批筆試”這幾個(gè)字的時(shí)候反而比第一批更緊張——因?yàn)檫@意味著網(wǎng)上已經(jīng)有很多人討論過題型和難度了你要是沒刷到這些信息等于裸考。我屬于那種考前一定要把信息都摸透的類型所以這篇復(fù)盤我會(huì)把“怎么準(zhǔn)備”、“考什么”、“怎么答”幾個(gè)層面串起來(lái)寫既記錄我的真實(shí)經(jīng)歷也盡量說點(diǎn)對(duì)后來(lái)人有用的東西。一個(gè)值得先說清楚的結(jié)論小米前端崗的筆試重點(diǎn)不在算法難不難而在基礎(chǔ)扎不扎實(shí)。它不像有些大廠上來(lái)就是hard題勸退但選擇題覆蓋面極廣手寫題又非常考驗(yàn)邊界意識(shí)整體風(fēng)格是“你好像都見過但一寫就漏”。這篇文章適合正在準(zhǔn)備秋招春招的前端同學(xué)也適合想了解大廠校招筆試真實(shí)節(jié)奏的朋友參考。1. 筆試前一周確認(rèn)形式、準(zhǔn)備環(huán)境、劃定復(fù)習(xí)范圍1.1 第一批考完后的信息收集我是第二批筆試時(shí)間排在工作日的晚上和第一批間隔了四天。這四天非常關(guān)鍵因?yàn)榈谝慌纪戤?dāng)晚牛客、脈脈、小紅書就會(huì)有人發(fā)帖子。我不是鼓勵(lì)大家去找原題而是要通過這些討論判斷三件事題量、題型分布、編程題用不用核心代碼模式。我當(dāng)時(shí)收集到的信息歸納下來(lái)是這樣的選擇題約二十道涵蓋JS基礎(chǔ)、CSS、瀏覽器原理、網(wǎng)絡(luò)協(xié)議、少量框架題編程題兩道一道偏手寫實(shí)現(xiàn)一道偏算法總時(shí)長(zhǎng)一百分鐘左右。這個(gè)信息幫我做了兩個(gè)決定第一復(fù)習(xí)重點(diǎn)從“刷難題”轉(zhuǎn)向“過基礎(chǔ)”第二提前在牛客上練了幾套模擬題適應(yīng)平臺(tái)那套代碼編輯器的手感。說實(shí)話如果你連考試系統(tǒng)都沒用過直接在正式筆試?yán)锘ㄊ昼姼忝靼状痤}界面怎么切題、代碼怎么運(yùn)行那太虧了。1.2 考試平臺(tái)與環(huán)境細(xì)節(jié)小米這批筆試用的是牛客的在線筆試系統(tǒng)。這類系統(tǒng)有幾個(gè)共同特點(diǎn)選擇題可以標(biāo)記回頭再看編程題只能本地調(diào)試后粘貼提交或者直接在網(wǎng)頁(yè)編輯器里寫。我建議編程題直接在網(wǎng)頁(yè)編輯器里寫因?yàn)楸镜鼐庉嬈饔写a提示、有習(xí)慣的快捷鍵一旦復(fù)制粘貼出了格式問題反而不容易發(fā)現(xiàn)。另外一個(gè)細(xì)節(jié)是攝像頭監(jiān)控。筆試要求全程開啟攝像頭環(huán)境要安靜、光線不能太暗桌面不能有筆和紙之外的東西。我當(dāng)時(shí)把桌面清理得很干凈連水杯都放地上了省的萬(wàn)一誤判就麻煩。還有一點(diǎn)容易被忽略提前測(cè)網(wǎng)速別考試中途斷線。我用的有線網(wǎng)絡(luò)把筆記本充電器也插好了因?yàn)楣P試和面試不一樣筆試一斷線系統(tǒng)可能直接判定交卷申訴流程極其折騰。1.3 復(fù)習(xí)范圍怎么劃一周時(shí)間不可能面面俱到我的策略是把高頻考點(diǎn)列出來(lái)按“必看、了解、放棄”三檔切分。必看的內(nèi)容包括JavaScript事件循環(huán)、閉包、原型鏈、this指向、異步方案演進(jìn)CSS三欄布局、flex與grid、BFC、層疊上下文HTTP緩存機(jī)制、跨域方案、瀏覽器渲染流程React Hooks使用規(guī)則、Vue響應(yīng)式原理的基本描述。了解的內(nèi)容包括TypeScript的泛型和工具類型、Webpack的loader和plugin區(qū)別、前端工程化常見概念。放棄的內(nèi)容包括復(fù)雜的CSS動(dòng)畫、Canvas底層API、Node.js服務(wù)端細(xì)節(jié)。很多人準(zhǔn)備校招筆試喜歡直接刷LeetCode但前端崗的筆試和純后端算法崗不一樣選擇題占比高考得雜只刷題不復(fù)習(xí)八股文等于只練了半條腿。我當(dāng)時(shí)每天把時(shí)間切成兩塊白天刷三到四道LeetCode熱題加看手寫題源碼晚上集中過兩到三個(gè)前端知識(shí)點(diǎn)畫成筆記。這套節(jié)奏比較適合筆試周期短的情況。2. 選擇題里的高頻考點(diǎn)哪些八股文值得背哪些可以放棄2.1 JavaScript語(yǔ)言特性考點(diǎn)小米這批選擇題里JavaScript部分大概占了百分之四十。具體來(lái)說閉包和this指向幾乎必考事件循環(huán)至少出現(xiàn)兩到三題原型鏈和new的實(shí)現(xiàn)邏輯也有一道。舉個(gè)例子關(guān)于this指向的題一般長(zhǎng)這樣給一段代碼里面有普通函數(shù)、箭頭函數(shù)、對(duì)象方法問最終輸出結(jié)果。這類題看起來(lái)很基礎(chǔ)但正確率其實(shí)不高因?yàn)榧^函數(shù)的this是在定義時(shí)確定的普通函數(shù)的this要看調(diào)用方式再加上嚴(yán)格模式和非嚴(yán)格模式的差異四個(gè)選項(xiàng)各有道理。我復(fù)習(xí)時(shí)會(huì)拿一張A4紙把所有調(diào)用方式列出來(lái)直接調(diào)用、對(duì)象方法調(diào)用、call/apply調(diào)用、new調(diào)用、回調(diào)函數(shù)調(diào)用每種情況對(duì)應(yīng)什么this寫上兩遍就記住了。事件循環(huán)的題則是另一個(gè)重災(zāi)區(qū)。它通常會(huì)混合setTimeout、Promise、async/await、微任務(wù)、宏任務(wù)還要考慮代碼的執(zhí)行順序。做這類題我有一個(gè)笨辦法先畫一條時(shí)間軸把宏任務(wù)按出現(xiàn)順序排好再在宏任務(wù)里面標(biāo)注微任務(wù)隊(duì)列。把Node環(huán)境下的process.nextTick和瀏覽器環(huán)境的queueMicrotask區(qū)別也理一下雖然筆試不一定考但面試一定會(huì)問。原型鏈的考點(diǎn)主要集中在構(gòu)造函數(shù)的prototype、實(shí)例的__proto__、以及Object.create的用法。我記得有一道題是給出一個(gè)繼承關(guān)系問某個(gè)屬性在哪里能找到屬于典型的“你懂原型鏈就秒選、不懂就全靠蒙”的題。建議把下面的代碼自己在腦子里過一遍過不了就動(dòng)手寫function Parent() { this.name parent; } Parent.prototype.say function() { console.log(this.name); }; function Child() { this.age 18; } Child.prototype new Parent(); Child.prototype.constructor Child;這樣設(shè)置的繼承Child實(shí)例可以調(diào)用say方法并且child.constructor指向Child而不是Parent。這幾個(gè)結(jié)論連在一起比死記硬背強(qiáng)得多。2.2 瀏覽器、網(wǎng)絡(luò)與CSS瀏覽器和網(wǎng)絡(luò)的部分占比也不低。HTTP緩存是必考項(xiàng)強(qiáng)緩存和協(xié)商緩存的字段要背熟Cache-Control的max-age、no-cache、no-store分別干什么ETag和Last-Modified的優(yōu)先級(jí)誰(shuí)高304出現(xiàn)的場(chǎng)景是什么。跨域問題也考了一道選項(xiàng)大概是從“CORS、JSONP、postMessage、WebSocket”里挑一個(gè)滿足某場(chǎng)景的方案。我記得還考了cookie和localStorage的區(qū)別、瀏覽器從輸入U(xiǎn)RL到頁(yè)面渲染的整個(gè)過程。CSS部分三欄布局那類題換了個(gè)外殼出現(xiàn)。不是直接讓你寫布局而是給一段flex代碼問最終效果。flex的flex-grow、flex-shrink、flex-basis組合起來(lái)確實(shí)容易迷糊建議復(fù)習(xí)的時(shí)候記三條規(guī)則flex-basis定基準(zhǔn)尺寸、flex-grow管放大比例、flex-shrink管縮小比例缺省值分別是auto、0、1。BFC也考了問的是哪幾種方式能形成BFCoverflow:hidden、display:flow-root、position:absolute這些都要能選出來(lái)。選擇題的特點(diǎn)是答案相對(duì)固定不需要寫理由但容錯(cuò)率低。每道題大概值兩到三分錯(cuò)五道就等于丟掉了一道編程題的分?jǐn)?shù)。我當(dāng)時(shí)給自己定的目標(biāo)是選擇題正確率百分之八十以上因?yàn)榫幊填}不確定性太高選擇題的分?jǐn)?shù)必須拿穩(wěn)。2.3 框架題的占比與應(yīng)對(duì)方式3. 手寫代碼題從用例設(shè)計(jì)到邊界條件的小坑3.1 防抖節(jié)流的兩種寫法對(duì)比3.2 深拷貝的完整實(shí)現(xiàn)與隱藏考點(diǎn)3.3 手寫題作答的展示策略4. 算法題復(fù)盤一道滑動(dòng)窗口題目的完整思考過程4.1 拿到題先問三個(gè)問題4.2 從暴力解到滑動(dòng)窗口的推導(dǎo)4.3 時(shí)間復(fù)雜度的取舍與筆試判題機(jī)制5. 筆試過程中的節(jié)奏管理和意外情況處理5.1 時(shí)間分配方案5.2 遇到不會(huì)的題和編譯報(bào)錯(cuò)怎么辦5.3 考后及時(shí)復(fù)盤為面試做鋪墊手寫題是前端崗筆試最有區(qū)分度的部分它不看你會(huì)不會(huì)背就看你能不能在白板狀態(tài)下寫出能跑的代碼。小米這批的手寫題風(fēng)格偏實(shí)用不像有些廠讓你手寫一個(gè)完整的Promise或者發(fā)布訂閱。我記得自己遇到的是兩個(gè)很經(jīng)典的題目方向防抖/節(jié)流的實(shí)現(xiàn)以及深拷貝的實(shí)現(xiàn)。這類題平時(shí)寫業(yè)務(wù)的時(shí)候經(jīng)常用到但真要你從零手寫很多人反而寫不完整。3.1 防抖節(jié)流的兩種寫法對(duì)比先說說防抖和節(jié)流。防抖的核心思想是“一定時(shí)間內(nèi)多次觸發(fā)只執(zhí)行最后一次”節(jié)流的核心思想是“一定時(shí)間內(nèi)最多執(zhí)行一次”。筆試的時(shí)候經(jīng)常讓你二選一或者先寫防抖再寫節(jié)流。很多人的誤區(qū)是背了一個(gè)版本結(jié)果沒注意是否支持參數(shù)傳遞、是否帶立即執(zhí)行選項(xiàng)。一個(gè)相對(duì)完整的防抖實(shí)現(xiàn)是這樣function debounce(fn, delay 300, immediate false) { let timer null; return function(...args) { const context this; if (timer) clearTimeout(timer); if (immediate) { const callNow !timer; timer setTimeout(() { timer null; }, delay); if (callNow) fn.apply(context, args); } else { timer setTimeout(() { fn.apply(context, args); }, delay); } }; }這個(gè)寫法里面有三個(gè)容易被忽略的細(xì)節(jié)第一this要保留很多面試官會(huì)追問箭頭函數(shù)能不能用在這里第二immediate參數(shù)控制是否立即執(zhí)行這個(gè)在實(shí)際業(yè)務(wù)里很常用比如按鈕點(diǎn)擊防重復(fù)提交第三定時(shí)器執(zhí)行完之后要把timer置空否則下一次callNow的判斷會(huì)出錯(cuò)。節(jié)流我常用時(shí)間戳版本function throttle(fn, interval 300) { let last 0; return function(...args) { const now Date.now(); if (now - last interval) { last now; fn.apply(this, args); } }; }時(shí)間戳版本有個(gè)特性第一次觸發(fā)會(huì)立即執(zhí)行最后一次觸發(fā)如果沒到間隔時(shí)間會(huì)丟掉。如果不想丟最后的調(diào)用可以用定時(shí)器版但筆試一般不會(huì)要求雙觸發(fā)邊界寫清楚一種加注釋說明即可。這類手寫題真正加分的地方不一定是你寫得多完美而是你代碼里體現(xiàn)了對(duì)邊界情況的思考。我在代碼注釋里標(biāo)注了“保留this指向”和“支持立即執(zhí)行選項(xiàng)”閱卷官假設(shè)是人工在看也會(huì)覺得你平時(shí)不是死記硬背是真正理解了這個(gè)工具函數(shù)。3.2 深拷貝的完整實(shí)現(xiàn)與隱藏考點(diǎn)深拷貝這道題看著簡(jiǎn)單其實(shí)考的是你的知識(shí)網(wǎng)夠不夠密。很多人一上來(lái)就寫JSON.parse(JSON.stringify())這當(dāng)然也是深拷貝但它的缺陷非常明顯遇到undefined、function、Symbol會(huì)被忽略遇到Date會(huì)變成字符串遇到循環(huán)引用會(huì)直接報(bào)錯(cuò)。如果筆試題目里面的測(cè)試用例包含這些類型這個(gè)寫法一定是過不了全部用例的。一個(gè)能覆蓋大多數(shù)場(chǎng)景的手寫深拷貝如下function deepClone(target, map new WeakMap()) { if (target null || typeof target ! object) { return target; } if (target instanceof Date) return new Date(target); if (target instanceof RegExp) return new RegExp(target.source, target.flags); if (map.has(target)) { return map.get(target); } const clone Array.isArray(target) ? [] : {}; map.set(target, clone); Reflect.ownKeys(target).forEach((key) { clone[key] deepClone(target[key], map); }); return clone; }這個(gè)版本里最值得說的就是WeakMap的使用——它的作用不是緩存數(shù)據(jù)而是處理循環(huán)引用。假如對(duì)象a里面引用了bb里面又引用了a不做處理就會(huì)無(wú)限遞歸下去。用一個(gè)WeakMap把已拷貝的源對(duì)象和克隆對(duì)象對(duì)應(yīng)存起來(lái)再次遇到同一個(gè)引用時(shí)直接返回之前克隆好的對(duì)象遞歸就終止了。還有Reflect.ownKeys這個(gè)API它會(huì)把普通字符串屬性和Symbol屬性一起枚舉出來(lái)這是Object.keys做不到的。如果考到Symbol作為屬性名的克隆用Object.keys的寫法直接漏數(shù)據(jù)。至于為什么用WeakMap而不是Map是因?yàn)閃eakMap的key是弱引用不會(huì)影響垃圾回收用Map在這個(gè)場(chǎng)景里也不會(huì)出錯(cuò)但面試官問了能答上來(lái)就是加分項(xiàng)。3.3 手寫題作答的展示策略手寫題和算法題在作答上有本質(zhì)區(qū)別。算法題只看結(jié)果對(duì)不對(duì)手寫題大概率存在閱卷環(huán)節(jié)代碼風(fēng)格、注釋、變量命名都會(huì)被看在眼里。我的策略有三個(gè)第一提前寫注釋。不是把整段代碼注釋滿而是在關(guān)鍵判斷處寫一句“// 處理循環(huán)引用”“// 保留this指向”讓閱卷人一眼看到你的思路。第二先用最保守的方式把核心功能跑通再補(bǔ)邊界。不要一上來(lái)就寫一個(gè)很復(fù)雜的版本結(jié)果語(yǔ)法都報(bào)錯(cuò)。第三考慮性能和可讀性的平衡。深拷貝用遞歸是標(biāo)準(zhǔn)做法但如果遞歸層數(shù)很深會(huì)棧溢出能提到用迭代法的思路作為后續(xù)優(yōu)化方向?qū)懺谧⑨尷镆沧銐蛄恕J謱戭}最怕的不是寫不出來(lái)而是寫了一半發(fā)現(xiàn)思路有問題劃掉重寫最后交上去的代碼只能用三個(gè)字形容——一團(tuán)糟。我建議先在草稿紙上把思路的關(guān)鍵節(jié)點(diǎn)寫出來(lái)再往編輯器里謄。算法題這部分我運(yùn)氣不算好遇到的一道題需要一點(diǎn)思考量但也沒有到勸退的地步。具體題目細(xì)節(jié)我記不太清了但類型是無(wú)重復(fù)字符的最長(zhǎng)子串算是LeetCode上的熱門題考的就是滑動(dòng)窗口這個(gè)經(jīng)典思路。這類題對(duì)有準(zhǔn)備的人是送分題但對(duì)沒刷過的人就是完全沒思路。4.1 拿到題先問三個(gè)問題看到算法題的完整描述之后我先逼自己回答三個(gè)問題輸入規(guī)模大概多大、返回的是什么類型的結(jié)果、有沒有明顯的特殊邊界需要單獨(dú)處理。輸入規(guī)模決定你能不能放心用O(n^2)的解法。如果n在500以內(nèi)暴力解可能都能過n到10^4基本就要往O(nlogn)下面去想了n到了10^5線性解法是必須的。有些筆試題會(huì)故意不給你數(shù)據(jù)范圍這時(shí)候默認(rèn)按比較大的規(guī)模處理優(yōu)先寫線性或近似線性的解法。邊界條件方面我每次都提醒自己檢查空字符串、全部字符相同、全部字符都不相同、字符串只有一位。這幾個(gè)用例分別覆蓋了滑窗的初始化、左右指針移動(dòng)、更新邏輯的極端情況。4.2 從暴力解到滑動(dòng)窗口的推導(dǎo)“無(wú)重復(fù)字符的最長(zhǎng)子串”這道題最直觀的解法是枚舉所有起始位置然后從每個(gè)位置往后擴(kuò)展擴(kuò)展過程中用Set記錄出現(xiàn)過的字符一旦發(fā)現(xiàn)重復(fù)就停止記錄當(dāng)前長(zhǎng)度。這個(gè)方案的正確性沒問題但最壞時(shí)間復(fù)雜度是O(n^2)當(dāng)字符串長(zhǎng)度到10^5級(jí)別的時(shí)候很大概率超時(shí)。滑動(dòng)窗口的思路本質(zhì)上是對(duì)暴力解的優(yōu)化既然右指針掃過的字符已經(jīng)記錄了左指針只需要重復(fù)字符出現(xiàn)之后跳過去不需要回到前面的位置重新遍歷。代碼寫出來(lái)就是一套雙指針加一個(gè)Setfunction lengthOfLongestSubstring(s) { const set new Set(); let left 0; let maxLen 0; for (let right 0; right s.length; right) { while (set.has(s[right])) { set.delete(s[left]); left; } set.add(s[right]); maxLen Math.max(maxLen, right - left 1); } return maxLen; }這段代碼的思路可以概括為右指針逐個(gè)擴(kuò)展窗口一旦遇到重復(fù)字符就把左指針往右移動(dòng)直到窗口里沒有重復(fù)字符為止。每次右指針移動(dòng)后都計(jì)算一次窗口大小不斷更新最大值。整個(gè)過程中左右指針都只往前走時(shí)間復(fù)雜度是O(n)。我當(dāng)時(shí)的思考路徑是先想到暴力解然后發(fā)現(xiàn)暴力解重復(fù)掃描了很多無(wú)效區(qū)間接著想到如果用Set記錄當(dāng)前窗口內(nèi)的字符左指針跳轉(zhuǎn)的時(shí)候就不需要從頭再來(lái)。這個(gè)過程也是面試官最想聽的“解題過程”但筆試只認(rèn)最終代碼所以如果你在注釋里寫清楚這是滑動(dòng)窗口閱卷觀感會(huì)好很多。4.3 時(shí)間復(fù)雜度的取舍與筆試判題機(jī)制筆試判題只看代碼能不能在規(guī)定時(shí)間內(nèi)跑完所有用例。你寫一個(gè)O(n^2)的暴力解如果全用例通過照樣滿分你寫一個(gè)O(n)的滑動(dòng)窗口只要有語(yǔ)法錯(cuò)誤照樣零分。所以筆試策略上優(yōu)先保證能跑通其次才追求最優(yōu)解。但如果時(shí)間允許我建議把暴力解和優(yōu)化解都留在草稿上實(shí)際提交時(shí)用優(yōu)化解。為什么因?yàn)橛行┕P試題的最后幾個(gè)用例是專門針對(duì)暴力解設(shè)計(jì)的超大數(shù)據(jù)暴力解跑不過去。我個(gè)人的習(xí)慣是前五分鐘寫一個(gè)暴力解確保思路正確然后立刻評(píng)估它的復(fù)雜度如果判斷可能會(huì)超時(shí)再寫優(yōu)化版本。另外一個(gè)經(jīng)驗(yàn)是盡量別用遞歸寫深度不確定的算法。遞歸雖然沒有硬件棧那么嚴(yán)格但在牛客這類系統(tǒng)里過深的遞歸會(huì)導(dǎo)致調(diào)用棧溢出而這道題完全可以用迭代寫。能用循環(huán)就用循環(huán)能不用遞歸就不用遞歸這是在線判題環(huán)境下最穩(wěn)妥的選擇。筆試現(xiàn)場(chǎng)的時(shí)間節(jié)奏其實(shí)比很多人想象得緊張。不是說題目難到做不完而是你需要在有限時(shí)間內(nèi)把會(huì)的題都穩(wěn)定發(fā)揮出來(lái)不因?yàn)榛艁y而丟分。這里分享一些我實(shí)際操作下來(lái)的時(shí)間分配和臨場(chǎng)策略。5.1 時(shí)間分配方案一百分鐘我的分配是這樣的選擇題控制在四十五分鐘以內(nèi)手寫題三十分鐘算法題三十分鐘最后留五到十分鐘檢查。選擇題遇到拿不準(zhǔn)的先標(biāo)記一下別死磕因?yàn)楹竺孀鼍幊填}時(shí)可能突然想起來(lái)某個(gè)知識(shí)點(diǎn)。編程題我習(xí)慣先把兩道題都掃一眼判斷哪道題更順手。手寫題和算法題如果水平差不多先做手寫題。手寫題是“熟悉題型”先把穩(wěn)定的分拿住算法題可能存在思路卡殼的風(fēng)險(xiǎn)放到后面心態(tài)會(huì)更穩(wěn)。但如果算法題一眼就看出了思路、手寫題反而沒把握那就按“先易后難”原則先做算法題。這個(gè)沒有絕對(duì)標(biāo)準(zhǔn)核心是先拿能拿的分。檢查環(huán)節(jié)被很多人忽略但實(shí)際上非常關(guān)鍵。檢查什么呢一是代碼有沒有未定義的變量二是有沒有邏輯邊界遺漏三是注釋和題目要求是否一致。有時(shí)候你在草稿上想的和實(shí)際寫進(jìn)編輯器的完全是兩回事用最后幾分鐘讀一遍代碼能挽回不少冤枉分。5.2 遇到不會(huì)的題和編譯報(bào)錯(cuò)怎么辦筆試時(shí)遇到完全沒思路的題最忌諱的是坐著發(fā)呆。我的做法是先把輸入和輸出用簡(jiǎn)單的示例跑一遍再嘗試用暴力解去套哪怕只能通過一部分用例也比零分強(qiáng)。有時(shí)候暴力解寫著寫著思路反而順了從暴力解優(yōu)化出正確解的情況并不少見。編譯報(bào)錯(cuò)則是另一回事。在線筆試系統(tǒng)對(duì)語(yǔ)法錯(cuò)誤的提示往往不如本地IDE友好報(bào)錯(cuò)信息看不太懂的時(shí)候先檢查幾個(gè)高頻錯(cuò)誤點(diǎn)分號(hào)是不是漏了、括號(hào)是不是匹配的、變量名是不是大小寫不一致。如果是運(yùn)行結(jié)果不對(duì)在關(guān)鍵位置插入一個(gè)console.log看中間狀態(tài)比靠肉眼看代碼快得多。還有一個(gè)容易被人忽略的坑牛客這類系統(tǒng)的輸入輸出格式是固定的。如果題目要求讀一行整數(shù)你的代碼寫成讀一個(gè)字符串再split會(huì)導(dǎo)致格式錯(cuò)誤。這類題我建議提前在牛客上練幾道輸入輸出模板題熟悉readline的使用方式別把時(shí)間浪費(fèi)在調(diào)試IO上。5.3 考后及時(shí)復(fù)盤為面試做鋪墊筆試結(jié)束不等于事情結(jié)束。我會(huì)在自己還能記住題目的時(shí)候把所有題目按“做對(duì)、做錯(cuò)、蒙對(duì)、沒思路”四類整理一遍。做錯(cuò)的題不一定是沒掌握可能是考場(chǎng)太緊張看錯(cuò)了題目條件蒙對(duì)的題更要重視因?yàn)槊嬖噯柕酵愋蛦栴}立刻露餡。整理完之后我會(huì)把每一類題目對(duì)應(yīng)到相應(yīng)的知識(shí)點(diǎn)判斷自己哪一塊是薄弱環(huán)節(jié)。“做錯(cuò)”的題涉及原型鏈那就抽時(shí)間重新過一遍原型鏈的常見問法“沒思路”的算法題是動(dòng)態(tài)規(guī)劃那就補(bǔ)幾道經(jīng)典DP題找感覺。這個(gè)環(huán)節(jié)看似消耗時(shí)間但實(shí)際上非常高效——它讓你下一次筆試或面試前的復(fù)習(xí)變得非常有針對(duì)性。還有一點(diǎn)考完出結(jié)果之前的空窗期一邊等通知一邊積累項(xiàng)目經(jīng)驗(yàn)別把秋招的節(jié)奏停在筆試結(jié)束。小米的面試一般會(huì)問項(xiàng)目、問基礎(chǔ)、問場(chǎng)景題筆試點(diǎn)出的薄弱點(diǎn)正好是接下來(lái)要補(bǔ)的面試考點(diǎn)。回頭看這場(chǎng)筆試我最大的感受是前端崗的筆試不拼題海戰(zhàn)術(shù)拼的是廣度夠不夠全、細(xì)節(jié)夠不夠細(xì)。選擇題考察的是你對(duì)常見API和原理理解的準(zhǔn)確性手寫題考察的是邊界意識(shí)和編碼習(xí)慣算法題則考察分析問題的路徑。這三個(gè)層面沒有一個(gè)是臨時(shí)抱佛腳能解決的都需要前面幾年或者幾個(gè)月的持續(xù)輸入。最后再分享一個(gè)小技巧筆試前我會(huì)把前端核心知識(shí)點(diǎn)的標(biāo)題列在一張思維導(dǎo)圖上考試中一旦遇到糾結(jié)的選項(xiàng)就在腦中定位到相應(yīng)的知識(shí)點(diǎn)分支回憶我當(dāng)時(shí)寫下的關(guān)鍵結(jié)論。這個(gè)方法幫我避免了很多“憑感覺做題”的情況也推薦給即將參加校招筆試的同學(xué)。