到筆試實(shí)戰(zhàn)的思維拆解)
作為一個(gè)經(jīng)歷過校招、也做過面試官的人我太清楚“京東2017校招編程題”在技術(shù)圈的分量了。那一年京東的筆試題目質(zhì)量相當(dāng)高雖然沒有特別偏難怪的題但勝在全面基礎(chǔ)、算法、思維一個(gè)不落。很多題后來被各大公司的題庫反復(fù)引用直到今天你在牛客網(wǎng)、力扣上依然能看到它們的變體。趁著最近又有不少讀者在后臺(tái)問我“校招編程題該怎么刷”、“京東的題難不難”我把當(dāng)年那套題重新扒出來結(jié)合我自己的解題記錄和后來做面試官時(shí)看到的考生常見錯(cuò)誤做一次系統(tǒng)的拆解。這篇文章不是簡(jiǎn)單地貼題目和答案而是想告訴你每一道題背后到底在考什么出題人希望看到你具備哪些能力以及當(dāng)你拿到一道陌生編程題時(shí)應(yīng)該用什么樣的思維路徑去拆解它。無論你是正在準(zhǔn)備校招的應(yīng)屆生還是工作幾年想回頭補(bǔ)基礎(chǔ)的同學(xué)這份梳理應(yīng)該都能幫到你。1. 京東2017校招編程題的整體畫像到底在考什么先給沒參加過那場(chǎng)筆試的同學(xué)還原一下當(dāng)時(shí)的場(chǎng)景。京東的校招筆試通常是線上筆試編程題部分一般有2到3道時(shí)間大概在1到1.5小時(shí)之間。你不僅要寫對(duì)還得寫得快、寫得穩(wěn)。2017年的題目整體風(fēng)格非?!熬〇|化”——?jiǎng)?wù)實(shí)、貼近業(yè)務(wù)場(chǎng)景、不追求偏怪難但對(duì)基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)和算法的要求一點(diǎn)都不含糊。1.1 核心考察方向基礎(chǔ)算法能力而不是炫技我那年刷完題后又把能找到的版本都做了一遍最大的感受是這組題考察的核心是“你是否具備扎實(shí)的計(jì)算機(jī)基礎(chǔ)功”。它的題目類型主要集中在字符串處理與模擬基礎(chǔ)動(dòng)態(tài)規(guī)劃圖論與搜索尤其是網(wǎng)格類場(chǎng)景數(shù)學(xué)推導(dǎo)與規(guī)律發(fā)現(xiàn)集合與哈希表的高效應(yīng)用你會(huì)發(fā)現(xiàn)它沒有那種要求你三分鐘默寫紅黑樹的變態(tài)問題也沒有需要半小時(shí)推公式的數(shù)學(xué)競(jìng)賽題。但它會(huì)把你要解決的問題藏在業(yè)務(wù)場(chǎng)景里。比如“分蘋果”、“找最少步數(shù)”、“字典序排列”這類題表面上是生活化描述骨子里考的卻是DP、BFS、貪心這些經(jīng)典算法。1.2 難度分布與題量結(jié)構(gòu)根據(jù)我找得到的真題回憶匯總2017年京東筆試的編程題大致呈階梯式分布第一題通常是純送分題考字符串操作或者簡(jiǎn)單模擬細(xì)心就能全對(duì)。第二題進(jìn)入中等難度一般是DP或者二分查找的變體需要你能準(zhǔn)確建模。第三題開始區(qū)分度就出來了要么是圖上搜索要么是帶有數(shù)學(xué)規(guī)律的構(gòu)造題需要你不僅會(huì)算法還能優(yōu)化常數(shù)。這三題做下來基本就能把一個(gè)候選人的編碼能力、算法功底、調(diào)試能力、心理素質(zhì)看得七七八八。說實(shí)話三年后我坐在面試官的位置上看候選人筆試代碼時(shí)依然會(huì)拿當(dāng)年這組題當(dāng)尺子。它不高級(jí)但真的能量出水平。1.3 為什么今天仍值得刷這套題有讀者可能會(huì)問2017年的題放到現(xiàn)在還有參考價(jià)值嗎我明確告訴你有而且價(jià)值不小。原因有三第一校招筆試的核心考察能力這些年沒有變依然是算法功底加編碼實(shí)現(xiàn)力。這套題的考察維度完全不過時(shí)。第二京東這套題在難度設(shè)置上非?!敖?jīng)典”既不像某些公司那樣入門勸退也不像另一些公司那樣全是模板題。它處在一個(gè)恰到好處的“能力探測(cè)區(qū)間”。第三這組題中的很多原題或變體后來反復(fù)出現(xiàn)在其他公司的題庫中。你刷熟了這一套等于同時(shí)做了好幾家公司的準(zhǔn)備。2. 高頻考點(diǎn)拆解把題目變成知識(shí)點(diǎn)地圖刷題最忌諱的就是“就題論題”。寫出一道題過兩天換了個(gè)皮又不會(huì)了。這本質(zhì)上是沒有完成“題目到知識(shí)點(diǎn)”的抽象過程。我當(dāng)年刷完京東這套題后專門做了一張知識(shí)點(diǎn)地圖今天分享給你。2.1 字符串處理類細(xì)節(jié)決定成敗這類題屬于“看起來簡(jiǎn)單做起來想摔鍵盤”的類型。京東的筆試?yán)镒址}經(jīng)常是第一題但它的坑從來不藏在算法里而是藏在邊界條件和特殊情況里。舉個(gè)例子當(dāng)時(shí)有道題是“給定一個(gè)字符串刪除其中所有重復(fù)字符且保持第一次出現(xiàn)的順序”。我見過很多人的第一反應(yīng)是“用HashSet邊遍歷邊去重”思路確實(shí)對(duì)但寫出來卻各種小問題有人忘了處理空字符串有人忽略了字符大小寫是否敏感有人沒有考慮字符集范圍。你去看官方題解會(huì)覺得這也太小兒科了但考場(chǎng)上全對(duì)的人就是不多。字符串題的復(fù)習(xí)重點(diǎn)應(yīng)該放在遍歷邊界、字符集范圍、輸入輸出格式、大小寫/空格的處理、以及代碼的健壯性。這些能力沒法靠背模板獲得只能靠大量手寫代碼形成肌肉記憶。2.2 動(dòng)態(tài)規(guī)劃與狀態(tài)定義區(qū)分度的分水嶺如果字符串題是熱身那動(dòng)態(tài)規(guī)劃題就是校招筆試真正的分水嶺。京東2017的題目里至少有三分之一的題需要用到DP思想。很多人學(xué)DP的通病是“狀態(tài)方程看不懂看懂了也不會(huì)推”。我提供一個(gè)親測(cè)有效的方法拿到一道DP題先別急著寫遞推公式而是先問自己三個(gè)問題我關(guān)注的結(jié)果是什么比如最大價(jià)值、最小步數(shù)、方案總數(shù)我在決策的過程中哪些信息是必須記住的這就是狀態(tài)維度的來源每一步?jīng)Q策和上一步的關(guān)系是什么這就是狀態(tài)轉(zhuǎn)移方程以京東考過的那道“分蘋果”來說很多人的第一反應(yīng)是搜所有方案但n一旦變大組合爆炸。用我上面的三個(gè)問題來拆解關(guān)注的是“最少搬動(dòng)幾次”必須記住“當(dāng)前蘋果數(shù)”和“已搬動(dòng)次數(shù)”每一步可以搬1、2或3個(gè)——這就是一個(gè)非常標(biāo)準(zhǔn)的“最少步數(shù)到達(dá)目標(biāo)”的動(dòng)態(tài)規(guī)劃模型狀態(tài)轉(zhuǎn)移方程其實(shí)就是dp[i] min(dp[i-1], dp[i-2], dp[i-3]) 1。我當(dāng)時(shí)在博客里寫過一句話今天依然覺得是對(duì)的動(dòng)態(tài)規(guī)劃不考智商考的是你有沒有建立“狀態(tài)”這個(gè)概念的習(xí)慣。2.3 圖論與搜索網(wǎng)格題里的陷阱與突破京東的題里還有一類非常高頻給定一個(gè)網(wǎng)格或者地圖求從起點(diǎn)到終點(diǎn)的最短路徑、最少步數(shù)、或者判斷是否可達(dá)。這類題幾乎就是為BFS量身定制的。但是請(qǐng)相信我這類題拿到滿分遠(yuǎn)比想象中難。因?yàn)榫W(wǎng)格題的坑不在算法本身而在工程細(xì)節(jié)。方向數(shù)組寫錯(cuò)了會(huì)導(dǎo)致全部走偏visited數(shù)組忘記標(biāo)記會(huì)導(dǎo)致隊(duì)列內(nèi)存爆炸對(duì)越界條件的判斷順序?qū)戝e(cuò)了甚至?xí)斐蓴?shù)組越界訪問。我當(dāng)時(shí)做過一個(gè)統(tǒng)計(jì)筆試中BFS題做錯(cuò)的人里有將近一半是掛在“邊界檢查”和“visited標(biāo)記”這兩個(gè)細(xì)節(jié)上。它不考你懂不懂BFS原理考的是你代碼寫得好不好。2.4 數(shù)學(xué)思維與規(guī)律題最后的亮點(diǎn)京東的題還有一個(gè)特色時(shí)不時(shí)會(huì)出現(xiàn)一道看起來像數(shù)學(xué)競(jìng)賽、實(shí)際上是編程題的題目。這類題往往是整套卷子的“小彩蛋”區(qū)分度極高。我印象最深的是一道跟“數(shù)字和”相關(guān)的題給定一個(gè)正整數(shù)每次操作可以將其替換為各個(gè)數(shù)位之和問多少次操作可以變成一位數(shù)。很多人拿到之后就寫循環(huán)、求數(shù)位和、再循環(huán)。這個(gè)沒錯(cuò)但如果出題人把測(cè)試數(shù)據(jù)范圍調(diào)大到10^18以上你的解法就需要優(yōu)化。這里其實(shí)藏著一個(gè)“數(shù)學(xué)優(yōu)化”的關(guān)鍵不是等數(shù)位和小于10才停下來而是直接用一次“數(shù)位和模9”的技巧判斷。類似的規(guī)律題你不知道這個(gè)規(guī)律時(shí)怎么寫都覺得別扭知道了以后三行代碼解決問題。這就是數(shù)學(xué)思維的價(jià)值。3. 典型題目精講從讀題到AC的完整推演前面講了考什么現(xiàn)在我們來實(shí)戰(zhàn)。我挑了幾道有代表性的題目帶著你走一遍從讀題到AC的完整思考過程。我不會(huì)只貼一個(gè)標(biāo)準(zhǔn)答案而是把每一步的思維過程、備選方案、以及我會(huì)踩的坑都攤開給你看。3.1 題目一數(shù)字序列拼接我們先從一道常見題入手。題目大致是給定n個(gè)正整數(shù)將它們拼接成一個(gè)新數(shù)問怎么拼接可以得到最大的數(shù)。比如輸入[3, 30, 34, 5, 9]能拼成的最大數(shù)是9534330。很多人的第一直覺是“按字典序從大到小排”但一提交發(fā)現(xiàn)連示例都過不了。問題出在哪因?yàn)椤?”和“30”這兩個(gè)數(shù)按字典序“3”的確比“30”大但拼接結(jié)果是330而另一個(gè)順序是303顯然前者更大??扇绻惆选?”和“98”放一起“9”字典序比“98”大但拼接“998”確實(shí)大于“989”所以這組又沒問題。你稍微多試幾組就會(huì)發(fā)現(xiàn)其實(shí)這是一個(gè)自定義排序問題。正確的做法是定義一個(gè)新的比較規(guī)則——對(duì)于字符串a(chǎn)和b如果“ab”大于“ba”則a應(yīng)該排在b前面。用Python寫的話核心就兩行from functools import cmp_to_key def largest_number(nums): strs list(map(str, nums)) strs.sort(keycmp_to_key(lambda a, b: -1 if ab ba else 1)) result .join(strs).lstrip(0) return result or 0這道題給我的啟發(fā)是當(dāng)直覺的排序規(guī)則不成立時(shí)不要死磕而是回到定義本身重新定義“誰在誰前面”的比較關(guān)系。這個(gè)思維模式不僅適用于這道題很多需要自定義排序的算法題都靠它。3.2 題目二快速求整數(shù)各個(gè)數(shù)位之和的實(shí)現(xiàn)這道題看起來像是來送分的輸入一個(gè)整數(shù)求它各位數(shù)字的和。有人會(huì)說這也算編程題但請(qǐng)注意當(dāng)測(cè)試數(shù)據(jù)的范圍達(dá)到10^18甚至更大的時(shí)候部分語言的基本類型就會(huì)溢出同時(shí)用字符串處理時(shí)的效率也會(huì)有差別。最穩(wěn)妥的實(shí)現(xiàn)方式是先轉(zhuǎn)字符串再逐位累加或者用取模運(yùn)算def digit_sum(n): total 0 while n: total n % 10 n // 10 return total這樣寫代碼非常短但對(duì)于極端的大整數(shù)如果題目允許用字符串輸入那么直接遍歷字符更穩(wěn)妥。我見過不少同學(xué)在考場(chǎng)上直接用int接收輸入然后發(fā)現(xiàn)溢出報(bào)錯(cuò)心態(tài)直接崩了。所以這種看似幼稚的題反而是最值得警惕的。通常這種“送分題”里還有隱藏考點(diǎn)比如數(shù)位和能不能被3整除、能不能被9整除。判斷某個(gè)數(shù)是否被3整除可以不用算完整數(shù)位和因?yàn)橐粋€(gè)數(shù)模3等于它的數(shù)位和模3模9同理。很多后來的筆試題都直接用了這個(gè)結(jié)論。記住有時(shí)面試官不是考你會(huì)不會(huì)循環(huán)而是考你知不知道背后的數(shù)學(xué)性質(zhì)。3.3 題目三帶狀態(tài)的網(wǎng)格最短步數(shù)問題這是2017年京東筆試?yán)镒钣袇^(qū)分度的一道題。題目描述是這樣的在一個(gè)m行n列網(wǎng)格中0表示空地1表示障礙物。玩家從左上角出發(fā)想到達(dá)右下角每次可以向上、下、左、右四個(gè)方向移動(dòng)。現(xiàn)在你有一個(gè)特殊能力可以使用一次使用后可以“跳過”一個(gè)障礙物。問最少需要多少步。如果你沒有做過帶狀態(tài)的BFS第一次看到會(huì)有點(diǎn)懵單純BFS求最短路徑可以但“可以跳過障礙物一次”這個(gè)條件怎么處理實(shí)際上這個(gè)題目需要把一個(gè)普通的節(jié)點(diǎn)狀態(tài)拆成兩個(gè)沒使用能力前和使用能力后。如果你在沒使用能力時(shí)到達(dá)某個(gè)節(jié)點(diǎn)但是后來你用掉了能力你的可選路徑就變了所以你不能僅僅用一個(gè)二維visited來記錄而要用三維數(shù)組visited[x][y][used]來記錄狀態(tài)其中used取0或1。搜索的過程是從起點(diǎn)開始如果當(dāng)前位置是空地兩個(gè)狀態(tài)都可以轉(zhuǎn)移如果是障礙物且未使用能力可以使用能力進(jìn)入used1的狀態(tài)如果是障礙物且能力已使用則不能進(jìn)入。終點(diǎn)可以是used0或used1的任意一種。由于BFS按層擴(kuò)展第一次到達(dá)終點(diǎn)時(shí)一定是最小步數(shù)。我當(dāng)時(shí)第一次寫這道題的代碼時(shí)因?yàn)榉较驍?shù)組的順序?qū)戝e(cuò)了導(dǎo)致搜索路徑不是最小卡了將近半小時(shí)。后來發(fā)現(xiàn)了這個(gè)低級(jí)錯(cuò)誤真的是哭笑不得。所以我真誠建議每位準(zhǔn)備筆試的同學(xué)方向數(shù)組最好固定為“上、下、左、右”和坐標(biāo)數(shù)組一一對(duì)應(yīng)就不要再改了免得自己把自己繞暈。認(rèn)真說這道題是BFS進(jìn)階的基礎(chǔ)也是很多“至少使用K次道具”問題的雛形后來我在不少大廠的題庫里都見到過類似模型。3.4 題目四股票買賣的最佳時(shí)機(jī)變體2017年京東也考過買賣股票的問題但它的變體比較特殊不是一次買賣也不是無限次買賣而是限定了最多兩次交易。原題通常是這樣說的給定一個(gè)數(shù)組它的第i個(gè)元素是一支給定股票第i天的價(jià)格。設(shè)計(jì)一個(gè)算法來計(jì)算你所能獲取的最大利潤最多可以完成兩筆交易。很多人第一次接觸時(shí)直接懵了不知道該從哪個(gè)角度拆。其實(shí)這個(gè)題是DP的經(jīng)典變體有兩種比較普適的做法。第一種做法是“分段法”因?yàn)樽疃鄡晒P交易一定存在一個(gè)分界點(diǎn)第一次交易在分界點(diǎn)左邊完成第二次在右邊完成。所以我們可以先從左往右預(yù)處理出“到第i天為止進(jìn)行一次交易能獲得的最大利潤”再從右往左預(yù)處理出“從第i天開始進(jìn)行一次交易能獲得的最大利潤”然后枚舉分界點(diǎn)答案就是兩者之和的最大值。用代碼來寫大概是這樣的def max_profit(prices): n len(prices) if n 2: return 0 left [0] * n right [0] * n # 從左往右 min_price prices[0] for i in range(1, n): left[i] max(left[i-1], prices[i] - min_price) min_price min(min_price, prices[i]) # 從右往左 max_price prices[-1] for i in range(n-2, -1, -1): right[i] max(right[i1], max_price - prices[i]) max_price max(max_price, prices[i]) ans 0 for i in range(n): ans max(ans, left[i] (right[i1] if i1 n else 0)) return ans第二種做法是狀態(tài)機(jī)DP。把整個(gè)過程當(dāng)成四個(gè)狀態(tài)第一次買入、第一次賣出、第二次買入、第二次賣出然后不斷更新。這個(gè)思路從原理上來說更通用擴(kuò)展性更強(qiáng)。但在這道題上分段法更好理解、編碼也更快應(yīng)對(duì)筆試更實(shí)際。這道題的價(jià)值在于它訓(xùn)練的是“把復(fù)雜交易拆成獨(dú)立可優(yōu)化的子問題”的能力。這個(gè)思路在后續(xù)很多難題里都能復(fù)用。3.5 題目五集合與哈希表的經(jīng)典配合還有一道印象很深的題是“給定一個(gè)整數(shù)數(shù)組找出其中沒有出現(xiàn)的最小正整數(shù)。”比如數(shù)組是[3, 4, -1, 1]答案就是2如果數(shù)組是[1, 2, 0]答案就是3。暴力解法很簡(jiǎn)單把所有數(shù)放進(jìn)哈希集合然后從1開始逐個(gè)檢查是否在集合里。時(shí)間復(fù)雜度O(n)空間復(fù)雜度O(n)。筆試?yán)镞@么做已經(jīng)能過了。但如果面試官追問“能不能做到O(1)空間”相信很多人會(huì)卡住。我當(dāng)時(shí)總結(jié)的O(1)空間做法是把數(shù)組本身當(dāng)成哈希表利用下標(biāo)與數(shù)值的對(duì)應(yīng)關(guān)系。具體思路是將所有在[1, n]范圍內(nèi)的數(shù)放到它對(duì)應(yīng)的下標(biāo)位置即讓nums[i] i1然后遍歷數(shù)組第一個(gè)不滿足的位置就是缺失的最小正整數(shù)。這個(gè)技巧叫“原地哈?!痹凇罢胰笔?shù)”“找重復(fù)數(shù)”這一系列問題里非常常用。Python代碼如下def first_missing_positive(nums): n len(nums) for i in range(n): while 1 nums[i] n and nums[nums[i]-1] ! nums[i]: nums[nums[i]-1], nums[i] nums[i], nums[nums[i]-1] for i in range(n): if nums[i] ! i 1: return i 1 return n 1很多同學(xué)看不懂這個(gè)while循環(huán)在干嘛。我解釋一下它做的事情是“不斷把當(dāng)前i位置的數(shù)交換到它該去的位置”直到當(dāng)前位置的數(shù)要么不在[1,n]范圍內(nèi)要么它已經(jīng)待在正確的位置上。交換后i位置又來了一個(gè)新數(shù)就繼續(xù)處理所以要套一層while。這道題展示了“如何用常數(shù)輔助空間解決看似需要哈希表的問題”也常作為面試現(xiàn)場(chǎng)手撕環(huán)節(jié)的考察題。刷透它能給你帶來不少底氣。4. 解題效率與代碼風(fēng)格如何讓閱卷官眼前一亮寫完題目答案只是第一步。我做過面試官之后才真正體會(huì)到閱卷官看一份筆試代碼時(shí)注意力是非常有限的。一個(gè)人如果代碼寫得清晰、規(guī)范、有注釋、邊界處理到位即使算法不是最優(yōu)解也能在閱卷官心里拿高分。相反即使AC了如果代碼一團(tuán)亂麻也容易被扣印象分。4.1 筆試中的高分段代碼長什么樣根據(jù)我的經(jīng)驗(yàn)?zāi)苣酶叻值拇a通常具備以下特點(diǎn)變量命名有意義。用i、j、k本身不是錯(cuò)但如果能用start、end、cur、prev這樣語意明確的命名閱讀體驗(yàn)會(huì)好很多。邊界處理前置??諗?shù)組、空字符串、只有一個(gè)元素的數(shù)組這一類特殊輸入的處理一定要在函數(shù)開頭就寫好。關(guān)鍵邏輯有注釋。不是說每行都注釋而是在狀態(tài)轉(zhuǎn)移、搜索剪枝、邊界判斷這些關(guān)鍵點(diǎn)用一行中文或英文點(diǎn)明你的思路。不做多余操作。一眼就能看出的無用代碼、重復(fù)計(jì)算比報(bào)錯(cuò)的代碼更讓人崩潰。我見過一位候選人在筆試卷上寫了一段BFS代碼里居然帶了完整的輸入輸出調(diào)試信息沒刪掉這給人留下的印象非常不專業(yè)??紙?chǎng)上時(shí)間再緊也一定要養(yǎng)成提交前清理調(diào)試代碼的習(xí)慣。4.2 從“能AC題目”到“高質(zhì)量編碼”的三個(gè)層次我把自己的編碼能力提升路徑總結(jié)成三個(gè)階段你看看自己在哪個(gè)位置第一階段能針對(duì)個(gè)別題目寫出正確答案但思路依賴“背模板”換一道新題就卡殼。第二階段能自主推導(dǎo)常見算法套路知道BFS、DFS、DP、二分這類算法分別適用于什么場(chǎng)景寫出來的代碼格式規(guī)范邊界問題考慮齊全。第三階段能通過建立“模型映射”把新題快速歸類為已知的算法模型并且能在有限時(shí)間內(nèi)完成編碼和驗(yàn)證。京東2017這組題恰恰就是幫你從第一階段走向后續(xù)階段的絕佳訓(xùn)練材料。它沒有超綱內(nèi)容也不依賴偏門技巧只要你認(rèn)真做、認(rèn)真總結(jié)每一題都能轉(zhuǎn)化為你的通用能力。我特別建議你把每道題都做三遍第一遍不設(shè)限怎么順手怎么寫第二遍限制時(shí)間模擬筆試環(huán)境第三遍嘗試用不同的解法來實(shí)現(xiàn)對(duì)比時(shí)間和空間復(fù)雜度。這樣做完一套題收獲會(huì)非常顯著。4.3 考場(chǎng)時(shí)間分配策略還有一點(diǎn)非常關(guān)鍵的考場(chǎng)心得編程題的題量通常不多但每道題需要調(diào)試的時(shí)間常常比你預(yù)想的長。我的建議是開考后先快速掃一遍所有編程題判斷每道題對(duì)自己來說是大題還是小題。如果遇到一眼就有思路的題盡快寫寫完了先別急著交留時(shí)間檢查邊界。如果遇到完全沒有思路的題先跳過去做后面的題保證能拿到的分一分不丟。等基礎(chǔ)題都AC了再回頭啃難題心態(tài)完全不同。一個(gè)我反復(fù)強(qiáng)調(diào)的細(xì)節(jié)是筆試系統(tǒng)一般要求你提交完整代碼而不是只提交函數(shù)體但很多在線編程平臺(tái)會(huì)自動(dòng)幫你處理輸入輸出所以你只需要實(shí)現(xiàn)核心函數(shù)。如果你不確定平臺(tái)規(guī)則第一題可以先花30秒做一個(gè)“空函數(shù)提交”測(cè)試看看返回什么再?zèng)Q定后續(xù)的寫法。這個(gè)技巧雖小但能幫你避免格式錯(cuò)誤帶來的無謂扣分。5. 常見問題與獨(dú)家避坑指南最后這個(gè)部分我把自己備考和后來輔導(dǎo)學(xué)弟學(xué)妹過程中最常見的坑給揪出來。這里面既有技術(shù)層面的也有心態(tài)層面的希望你能繞開。5.1 刷題數(shù)量至上方向跑偏的典型表現(xiàn)“我刷了500題為什么筆試還是掛”每次聽到這句話我就想問你是刷了500題還是把同一道題做了500遍刷題的作用不是讓你“見過更多題”而是讓你“在遇到?jīng)]見過題時(shí)有足夠的解題套路可用”。我見過太多考生寫了一道京東真題看完題解覺得“哦原來是DP”然后馬不停蹄刷下一題。這是完全無效的。正確姿勢(shì)是做完一道題后至少做三件事——第一不看題解重新寫一遍第二總結(jié)這道題屬于哪個(gè)算法模型第三找到一兩道同類型的題趁熱打鐵鞏固。所以不必貪多能把京東這套題做到這種程度筆試基本就穩(wěn)了。5.2 閱讀輸入不仔細(xì)最容易控制的高頻扣分點(diǎn)京東的筆試題有一個(gè)特點(diǎn)就是題干往往較長有很多業(yè)務(wù)化的描述。有些同學(xué)讀題讀到一半就迫不及待開始編碼結(jié)果寫完才發(fā)現(xiàn)“哦原來輸入不止一組數(shù)據(jù)”或者“原來要按照字典序輸出”。我的習(xí)慣是讀題階段至少花兩分鐘把第一段題目描述和最后一段輸入輸出說明都完整看完再動(dòng)手。如果題目上說“多組測(cè)試數(shù)據(jù)”就要記得外層套一層while循環(huán)。對(duì)這種問題我建議你在草稿紙上寫下輸入類型、輸出要求、邊界條件、是否多組四個(gè)要點(diǎn)再動(dòng)筆。5.3 過度追求最優(yōu)解筆試中的隱形殺手剛刷題的人容易陷入一種心態(tài)看到一道題總想找到傳說中的“最優(yōu)解”仿佛不用上最高級(jí)的算法就對(duì)不起這道題。但筆試拼的是分?jǐn)?shù)分?jǐn)?shù)是按測(cè)試點(diǎn)算的。你能用O(n^2)的算法AC一個(gè)n10^4的題你是拿滿分你用O(n)的算法想了半小時(shí)沒寫出來你拿零分。我見過不少真實(shí)案例都是因?yàn)椤跋朐诳紙?chǎng)上給一個(gè)優(yōu)雅解”反而把時(shí)間耗盡。正確的策略是先寫暴力解法拿基礎(chǔ)分再考慮優(yōu)化。暴力解并不是丟人它在很多情況下是通往最優(yōu)解的第一步。5.4 真題和變體之間的學(xué)習(xí)留白還有一個(gè)秘密很多人刷真題時(shí)沒有意識(shí)到京東這套題中的很多題后來都在其他公司的考試中“換殼登場(chǎng)”。比如股票買賣、網(wǎng)格最短步數(shù)、最小正整數(shù)缺失分別套過“兼職賺錢”“尋寶地圖”“整理工牌”之類的故事外殼。所以學(xué)習(xí)時(shí)務(wù)必把題目還原成算法模型來記憶看到“求最少步數(shù)”聯(lián)想到BFS或DP看到“最大利潤”聯(lián)想到狀態(tài)機(jī)或二分貪心看到“缺失數(shù)字”聯(lián)想到原地哈希或位運(yùn)算。背書是背不完的但把模型練熟了萬變不離其宗。5.5 心態(tài)與健康筆試最后的隱形競(jìng)爭(zhēng)力最后一個(gè)看似和編程無關(guān)、實(shí)際上非常影響發(fā)揮的點(diǎn)就是身體狀態(tài)和心態(tài)。筆試通常需要連續(xù)高強(qiáng)度用腦兩小時(shí)如果前一晚熬夜刷題第二天精神狀態(tài)一定很差。我自己當(dāng)年筆試前夜就是失眠加焦慮第二天寫代碼的時(shí)候腦子像灌了漿糊本來能做出來的題愣是卡了四十分鐘。后來我給自己定了一個(gè)規(guī)矩筆試前一天不再碰新題只簡(jiǎn)單復(fù)習(xí)筆記和錯(cuò)題晚上11點(diǎn)前上床不帶手機(jī)進(jìn)臥室第二天開考前做十分鐘深呼吸。這個(gè)習(xí)慣一直保留到我后來工作后的每一次線上技術(shù)考核。聽起來很玄學(xué)但實(shí)測(cè)非常有效。基本功是平時(shí)積累的考場(chǎng)上比的是誰發(fā)揮得穩(wěn)。把自己調(diào)整到能打出全部水平的狀態(tài)比多刷十道題重要得多。京東2017校招編程題這套題我一直認(rèn)為它是校招筆試訓(xùn)練的“黃金材料”難度適中、考點(diǎn)全面、和業(yè)務(wù)結(jié)合緊密。如果你正在準(zhǔn)備技術(shù)崗校招不妨把這套題認(rèn)真吃透甚至可以做上兩遍三遍。這個(gè)過程中收獲的絕不僅僅是幾道題的答案而是一套能陪伴你整個(gè)職業(yè)生涯的算法思維和編碼習(xí)慣。