大家對 Leetcode (或是演算法題)太多誤解,像是要把 Leetcode 所有題目背起來再去面試、演算法題是智力測驗 (所以無法透過練習而增進解題能力)。很多人批評演算法面試跟工作脫節,不過我們沒辦法控制每一家公司如何面試人選,討論這個對於通過面試一點幫助也沒有。這邊想分享我如何「刻意練習」演算法,三個月從 1664 分打到 2146 分。
Leetcode
Leetcode 是一個線上解題的網站,上面蒐集了許多軟體公司面試會問的演算法題。目前演算法有兩千多題,如果不是全職找工作不可能每題都寫完、甚至是背起來,也不需要每題都寫完。有一個每週舉辦一次的例行比賽,一個每兩週舉辦一次的例行比賽,比完賽以後題目會放進題庫,所以未來題目只會越來越多,寫完所有題目要花的時間只會越來越多,但也完全沒有必要寫完所有題目。
週賽
Leetcode 有兩個定期比賽,一個在台灣時間週六晚上十點半,每兩週一次,另一個是在台灣時間週日早上十點半,每週一次。每個人一開始 rating 都是 1500 分,比賽結果的排名這個分數應有的排名好就會加分,超出越多加越多分,相反的就會扣分。比過夠多場比賽且你的實力沒有改變的話,這個分數就會收斂不再變動。
強烈建議參加週賽以了解自己真正的實力,以及熟悉如何在時間壓力下解題。週賽 rating 也是觀察自己實力進步的一個方法,如果連續幾場比賽 rating 都沒提升甚至是降低,就要檢視一下自己的練習方法是不是有什麼問題。週賽 rating 可以大致反應一個人的實力,而解題數幾乎沒有辦法,不要再看解題數了!每次比賽會有四題,一題 easy、一題偏簡單的 medium、一題偏難的 medium、一題 hard。參加比賽也可以獲得 Leetcode point,可以用來換免費的 premium 會員資格。
刻意練習
刻意練習只有一個重點:進步最快的方式就是在比自己舒適圈更困難一點的地方練習。因此步驟如下:
- 找到自己的程度在哪。
- 找到比自己程度稍高一點的題目。
- 重複練習 2 找到的題目,熟悉以後表示自己程度提高了,可以再找更困難一點的題目練習。
Leetcode 週賽可以幫助我們找到自己的程度在哪,下面會介紹題目 rating 的工具幫助我們找到比自己程度稍高一點的題目。已經會的題目就不需要浪費時間去寫了,寫再多也只是在練習打字速度而已,不會對解題能力有任何幫助。所以 Leetcode 寫過幾題並不重要,重要的是哪些難度的題目可以靠自己獨立解出來。
Leetcode Assessment
Leetcode 有一個 assessment 功能,在 interview tab 下面,它會隨機選擇題目組成題組,給一段時間讓我們作答。結束以後會根據答對的測資數、上傳次數、解題速度給一個評分。這個分數不是很重要,重點是它有一個 insight 功能會根據作答情況分析我們在哪個主題表現比較好或是比較差。表現最好是 Looking good
,次好是 Getting there
。功能很好,因為我們寫題目的時候不知道這題屬於哪個主題,跟面試、比賽的時候是一樣的,而它又會告訴我們哪個主題程度如何,可以依此來決定練習量跟題目難度。通常以我來說,Looking good
的主題可以直接練習 hard 難度的題目,Getting there
可以從 medium 難度的題目開始。但有時 Leetcode 的題目難度分類不是很準確,還是要練習稍微超出自己程度的題目才真的有練習到。
Leetcode Problem Rating
Github 上有一位 zerotrac
大大根據每次週賽題目解出人數算出第 63 場週賽以後每題的 rating。使用的基本概念是 Elo 評分系統:一個題目被很多一般 rating 人解出來表示很簡單,所以 problem rating 應該要比較低;如果只被高 raing 的人解出來表示這是難題,所以 problem rating 應該要比較高。具體來說,rating $x$ 的參賽者解出 rating $y$ 的題目的機率為 $\frac{1}{(1 + 10^{\frac{y-x}{400}})}$,參賽者跟題目 rating 一樣的話,解出機率就是 0.5。
練習時可以找比自己 rating 高 50 到 100 分的題目來練習,根據我的經驗,這個難度比 Leetcode 給的難度準確很多。每個人不一定在每個主題都一樣擅長,舉例來說,可能有些人 graph 比較擅長就可以找比自己 rating 高兩百分的題目練習,bitwise manipulation 比較不擅長就可以找比自己 rating 低一百分的題目練習。核心概念是在比自己舒適圈更困難一點的地方練習。
練習方法
以下是我的練習方法:根據前段方法選出稍微超出自己能力的題目來練習,因為是稍微超出自己的能力,所以大多數時候應該是有辦法花一些時間自己努力寫出來。如果努力一到兩個小時以後還是想不出來,可以看一下題目的主題 (演算法),如果還是想不出來有些題目會有提示可以看,看了提示還是想不出來再到討論區看其他人的解法。理解解法以後,試著自己重新解一遍,然後把題目記下來,過一到兩週忘記別人的寫法以後再嘗試自己解一次,避免用背的而不是真正理解。
就算有自己解出來還是要看討論區,看看有沒有複雜度更好或是更優雅的寫法。有的話一樣把那個解法自己練習一次。
Premium 會員
Premium 會員有兩個主要功能:
- 上傳頻率無限制。
- 可以知道這題有哪間公司考過,以及某些題目要有會員才能寫。
我認為不需要買。就算偶爾被卡上傳頻率,也只要等兩三秒。
第二點,因為我們的目標不是要把每一題都背起來,而是要有能力自己解出題目。當練習到有能力自己解出題目時,就算面試看到的題目是以前沒寫過的,還是有辦法靠自己寫出來。而且現在題目越來越多,剛好遇到寫過的題目的機會會越來越低。
面試
演算法面試跟寫演算法題目有一個不一樣的地方,演算法題會定義好輸入的範圍,所以可以根據這個範圍大概知道可以使用多少時間複雜度的演算法,但面試通常不會給這個資訊。而且面試時需要跟面試官交流想法,不是默寫一個最佳解出來就好了,所以還是需要找人幫忙模擬面試。
基本上只要可以穩定在面試時間內解出 medium 難度的題目就足以通過大部分的演算法面試。能夠穩定在週賽 40 分鐘內解出前三題 1 easy + 2 medium 就足以通過多數面試了。如果面試還是過不了,通常不會是題目解不出來造成的。
Happy Leetcoding!