大家都是如何刷 LeetCode 的?


從第一題Two Sum開始,默默刷了一年多,算不上經驗吧,就是我自己的一點碎碎念。沒什麼條理,想到哪兒寫到哪兒。

刷題我見過兩種流派,一種【兔系】,一種【龜系】

【龜篇】

我自己是比較偏「龜系」的刷法【傳送 &>ciaoshen.com】從一開始為了找工作,每天4,5題,到後來慢慢變成一種習慣,每天早上起來,喝兩口咖啡先來一發。我個人比較信奉Peter Norvig的 「十年理論」。之前Dave Thomas提出的 」Code Kata「 也是類似的概念,核心理念就是 「刻意訓練」 。現在刷leetcode就是我堅持的「刻意訓練」的一部分。日常工作里調調參數,修修Bug,用用框架實際上達不到」刻意訓練「的標準。像leetcode這樣的OJ正好提供了這樣一個」道場「不是很好嗎。

我們有的時候過分注重了演算法題的「演算法意義」,而忽略了」工程意義「。題刷多了就知道,常用套路其實來來回回就那麼幾個。但明確了演算法,能不能準確地實現,做到bug free又是另一回事。再進一步,數據結構用的合不合理,也會影響最終效率。代碼寫出來,別人好不好懂,又是另一個層面的要求。最後要參加面試,又必須在規定時間裡完成,不但要寫的快,代碼還要乾淨,符合工程規範。

所以」龜系「刷法的精髓就是每個題目要做乾淨。不要滿足於一種解法,各種解法都寫一寫。我現在accept了350+題,用了1000多種方法。平均每題2~3個Solution。基本每題都做到beats 90+%

350+Problems / 1000+Solutions

最好不要滿足於accept,要追求最高效率。做一題就要殺死一題。leetcode不是給了運行時間的分布嗎,基本上每個波峰都代表了一種特定複雜度的演算法,中間的起伏體現的就是具體實現細節的差距。每次都要向最前面的波峰努力啊&>.&<。追逐最前一個波峰的過程不但鍛煉演算法,還鍛煉數據結構,鍛煉對庫函數的熟悉程度。經常比較不同數據結構不同庫函數的效率,時間久了能產生一種直覺,以後一出手就是最優選擇。(小貼士:點開豎直的分布條,是可以看到對應代碼的,對學習高手的解法很有幫助。)

但「龜系」不是說在一道題上耗死。越是龜系越要注意時間上要掌握好分寸,能解出來最好,解不出來也不要倔強。我覺得比較好的一個平衡點差不多是「一個小時」。如果一個小時還是解決不了可以點開右邊Related Topics鏈接看提示。還是不能解決就看討論區。

現在一年多堅持下來,最大的收穫不是知道了多少演算法套路,而是代碼硬能力上的進步。之前經常會卡在一些實現細節的地方,現在只要整體方向確定下來業務邏輯捋清楚,具體實現編碼反而是最輕鬆的工作。這就是為什麼大廠面試要考演算法。功底好的工程師才有精力騰出來考慮工程,產品方面的問題。

【兔篇】

「兔系「更加符合」刷題「的說法,就是按標籤刷,按公司刷。今天做binary tree就一下子做10,20題。很多人可能對這個做法有點抵觸,覺得太功利,沒有思考的過程。當初我也有這個偏見。但後來發現很多最後拿到FLAG offer的大神都這麼干。而且過程之暴力令人髮指。記得有個大神刷到第三遍,每天可以做80+題。拿到題根本不思考,直接在自帶編輯框開始碼,而且還基本做到bug free。

我也不知道他是不是在吹,但「兔系」的精髓就是要暴力,天馬流星拳,大力出奇蹟。有的人提倡」不要看答案「。這種觀點我覺得是對的,像我自己就很少看答案。但作為兔系選手,講求的就是要瘋,不如一上來就看答案,就照著答案寫。這個做法看起來不靠譜,其實它有內在的合理性:大部分演算法都不是我們發明的。什麼動態規劃,二叉樹,線段樹,並查集,貪心演算法,到後來所謂的不看答案自己做出來,其實都是在用固定套路。到最後你看那些acmer高手,看似思路很快,其實就是知道的套路比你多,而且不是多一點。所以既然明確了是為了找工作的目標,那就放下矜持,放下承見,拿到offer比什麼都強,哪怕是以一種羊癲瘋的姿勢。

最後,刷題呢工具一定要用起來。比如我用Java刷,什麼ant, gradle, junit, log4j, slf4j都用起來。可以省去很多搭環境,搭框架的時間,把精力都集中在解決演算法上。leetcode最近出了一個Playground我就覺得很好呀,直接在網頁上寫代碼省去了很多麻煩。但我也提個小意見,就是如果能更完整地支持vim就更好了。現階段我還是不得不自己開編輯器。這裡給大家安利一個一鍵生成"Solution/Test"框架的小工具leetcode-helper

helloShen/leetcode-helper?

github.com圖標

下載地址(最新v0.55):

  • 【leetcode-helper-v0.55.tar】
  • 【leetcode-helper-v0.55.tar.gz】
  • 【leetcode-helper-v0.55.zip】

一行命令ant generate,生成支持Junitlog4j/slf4jSolution/Test/TestRunner 骨架類,

一行命令生成Solution以及Junit單元測試骨架

一行命令ant compile test,實現編譯以及JUnit單元測試。

一行命令編譯,運行JUnit單元測試

而且附帶了一個leetcode常用數據結構包com.ciaoshen.leetcode.util。 像常用的比如ListNodeTreeNode的基本實現都有了。

現在每天早上拿著我的煎餅果子和咖啡,一鍵生成骨架,開編輯器就坐下來寫演算法,然後一鍵測試,提交。然後該幹嘛幹嘛。leetcode真的成了我的一種生活方式。不求名,不求利,但求無愧於心,干一行愛一行。


我學完了c++,數據結構,演算法就開始刷leetcode上的演算法題。

我是按照tag來刷,剛開始的時候看了一下tag里的分類,選擇從遞歸開始,因為對我來說遞歸好理解比較簡單,所以從自己喜歡的類型,是希望這是一個好的開始。

選好tag後,我從hard題(不帶鎖)開始做,因為喜歡從難到易。

第一題leetcode就是是Number of Atoms,我做題是在紙上畫一個大概流程,畫了圖後會有一個對程序比較直觀的理解,然後順便寫上偽代碼,偽代碼就是有方框圖有標記一些變數該用什麼循環之類的關鍵詞,如果遇到卡殼的地方,我會google,然後看一下人家的解題(先不去理解,因為還要再掙扎一下看自己能不能解決這個卡殼),一眼快速掃過看看有沒有關鍵詞提示詞,舉個例子比如看到了map,那我就回顧一下之前所學過關於map的內容,再看一下自己的偽代碼有沒有用得上的或者需要修改的,有需要的話就會用上。有時候有些語法的東西忘了,我就順便看一下《c++ primer》相關的知識點,假如這次看了某章某節,就在用mind node里的樹狀筆記補上。

目前才做完recursion的兩題hard題,沒有讓我灰心喪氣不想做題。不過我的c++用的不是很熟練,希望刷完hard題之後我的代碼能力會提高。

下一個tag就是刷map的題,因為map剛複習過;或者動態規劃吧,因為動態規劃也會用到遞歸,而且題比較多,躍躍欲試中。明天就可以開始啦,期待地搓搓手。

圖是我的c++ primer筆記。


我的刷題經歷大概分成下面幾個階段:

第一階段,16年暑假,註冊了leetcode,時間比較充裕有兩個月。因為不是CS科班(EE),就按照easy&>&>medium&>&>hard的順序,語言用的cpp,題目範圍是前300道。刷完easy熟悉了cpp的語法以及STL的用法。之後再做medium,藉此過程重溫了經典的數據結構和演算法,再然後是hard。刷題節奏大概是easy每天12道,medium8道,hard隨緣2~4道。每道題提交之後會檢查運行時間的統計圖,如果發現相對很慢,會去discuss上看別人的解法思路,然後自己寫一遍提交。查看discuss的情況還包括:自己的代碼寫的很繁雜,邏輯不清晰,自己又理不順時;題目的tag里提示有別的解法時;想了半小時以上沒思路時。

之後一年也斷續的刷題,但不成規模。

第二階段,17年春夏,按題目分類(bfs, dfs, dp ...)把做過的題再總結一遍,每個類別寫了筆記。總結的原因是,刷題時有「似曾相識」,卻又「朦朧」的感覺。這一遍總結了很多常用的演算法snippet和套路,基本爛熟於心。對於每個分類,也是按easy&>&>medium&>&>hard的順序過的。

第三階段是近期才開始的,每周六參加leetcode contest,雖然水平差只能AC三道題,但會盡量獨立在contest結束後做出第四道提交(實在沒思路就去discuss上學習以下)。當天會寫一篇contest解題筆記,給自己看的寫的簡略,但會分析一下遇到的問題,discuss上有好的思路也會記下來。


鹹魚系LeetCode用戶在此…說是鹹魚是平時極少系統化高強度練習,只是每周在周周練里爭取做出3題,衝刺4題… 是從一年前為了面試把LeetCode的兄弟網站LintCode上的題刷了300題之後開始的。

因為沒有參加過ACM,所以現在還是經常做不出最後一題的水平,不過覺得看著這個曲線覺得心裡還是有點高興的。從曲線的趨勢看來,已經到了一個瓶頸,需要去想辦法上一個新台階。


刷了一年半,目前刷過了800+的題。

周賽迄今參加了75次,其中9次前50,18次前100,28次前200.

北美生物醫學的Phd,工作非cs領域。高中有一點信息學競賽的基礎,高考之後到phd畢業之前的4+3+6=13年沒做過一道演算法題。

———————

2018.11.30 更新: 在十一月的一次LC周賽(本人的第81場周賽)中取得了第三名。同時這個月底簽了狗家。刷題並不是人生的全部,打算金盆洗手了。


推薦閱讀:

TAG:面試 | 演算法 | 數據結構 | LeetCode領扣 | 刷題 |