Leetcode 百題練習心得 – 寫給跟我一樣,不曉得為何要練習演算法,或是不曉得怎麼開始練習的伙伴們。

為什麼要學?

首先來看看為什麼要學習演算法?作這件事的價值在哪裡?
在學校就上過演算法,但那時候不懂演算法是什麼,也不懂為何要學;
開始工作後,常看人家說 dsa ( 資料結構 & 演算法 ) 很重要,試著打開leetcode寫了幾題,無感;
曾在學新語言的時候試著用 leetcode 來熟悉語法,仍然是沒什麼回饋;
也去討論區問過「學演算法是不是一般碼農級的工作用不到?」這種蠢問題。

後來因為想換工作,又再度打開 leetcode ,這次有系統的練習,結果在約莫50題的時候就開始感到有成效了:
首先當然是因為自己能解出題目的成就感,再來是開始可以應用在公司既有的程式上,甚至在聽演講的時候看著電視牆在腦中思考矩陣相關演算法的實作 (欸?


應用實例 1

曾經在公司接過這麼一個小型的 PHP 專案:網路上的文章說 in_array() 的效能不好,建議用array_flip() 把key / value 交換後改用 isset() 來增進某支 API 的效能。如果當時的我有現在的知識,就可以更明確的了解 in_array() 的時間複雜度是 O(N) , isset() 則是 O(1),而不是模糊的「好」、「不好」。

但實際開始作才發現,原本寫這支程式的人用了nested loop,把它實作成 O(N²),那又是另一段辛酸血淚了…

應用實例 2

公司有一款類似 candy crush 的遊戲,其中「從遊戲盤面上找出同樣的元件、消除後從上面落下新的元件」這兩個演算法,原本都是暴力解,在我改寫過後執行時間只剩下原本的 25%,而其中「落下新元件」的這一段就是使用了 two pointer ,把原本的 O(N²) 降低為 O(N)。

如何練習?

這次練習使用的是leetcode + golang ,但我想使用其他語言及工具應該也大同小異:
首先,萬一還不熟悉的話,先了解常見的資料結構: array, hash table, stack, queue, linked list, binary tree
接下來一次選一個 tag 開始練習,一次選10題左右,我是用 array -> string -> math -> list -> tree 的順序開始,這樣可以幫助自己熟悉各種解題的 pattern。
打開題目先試著用紙筆(有白板更好!)思考一下問題、限制條件及可能的解法,先用暴力解也沒關係,之後再調整就好
我都會設定一個30分鐘的計時器,如果卡了太久都沒有進展,就直接看看 solution 或是 discuss 看一下別人怎麼解,有時候不會的東西就是不會,想破腦都想不出答案的。
如果能順利解出來,就分析一下解法的時間及空間複雜度,一樣再去看看有沒有其他解法,discuss 裡面有很多讓人感受到實力差距的答案 QQ

我是都會在本機用 tdd 的形式來寫,能通過所有測試再用 leetcode submit,這樣子能否通過的回饋比較快,也能減少 wrong answer 的挫折感,
但如果目的是面試,很多公司是指定答題的平台,也有聽說會用協作平台直接看你寫 code 的,所以在各平台上直接寫出 bug-free 程式碼的能力還是要練習一下。
我的GitHub repository ,希望能給一樣想先在本機寫完再 submit 的伙伴一些靈感

簡單的說:

  • 一次選定一個主題來練習
  • 解題前先思考,並用紙筆或白板敘述
  • 實作解法,看是不是可以通過
  • 解出來後分析複雜度,嘗試能不能改善
  • 解不出來也沒關係,學習別人怎麼解的,抄一次先
  • 用 tdd 的模式,試著自己想一些 edge cases 加入測試

有時候你用的語言 standard library 就會內建能解題的 function 了,像是 php 有很多 str 跟 array 的工具,或是常看人家說的 life is short, use python 之類,拿去 Submit 看看也無傷大雅,說不定自己重寫還更慢…

寫這篇文章的時間點,leetcode 上有 1617 題,我們的目的不是要把他全部寫完,當你覺得可以掌握某種 pattern 之後,記得要往更難的題目挑戰,leetcode 上的難度或通過率都可以參考。

references

學習的路上參考過的資源:

知乎的討論

quora 的討論

演算法筆記

second round

最後修改日期: 2021-04-15

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。