背景
如果前人認為這個一種學習提高或者檢驗能力的成功實踐。而自己目前又沒有更好的方法,那就不妨試一試。
而不管作為面試官還是被面試者,編碼題最近越來越流行。而兩種角色都需要思考的問題是希望考察什麼能力,通過什麼題目,需要達到怎樣的程度可以說明面試者具有了這樣的能力。
而要找到上面這些問題的答案,比較好的方式除了看一些理論性文章和接受培訓之外,自己動手刷一刷leetcode切身實踐一下不失為一個不錯的方式。而既然要花精力去做這件事情,那就需要解決一個問題:我從中可以獲得什麼提高。以下是個人的一些經驗和感受。
收益
對底層有了更深入的瞭解和思考
leetcode一些常見題也是平時工作中常用的一些底層資料結構的實現方法。
先舉個大家使用比較多的演算法:LRU(最近最少使用),在Java的實現中實現特別簡單。只是使用了LinkedHashMap這種資料結構。而如果看一些開源包裡LRU的實現,發現也是這樣實現的。實際上動手實現一遍,LRU就再也不會忘了。
再舉個資料結構的例子:字典樹又叫字首樹。它是搜尋和推薦的基礎。標準點的定義是:
字典樹又稱單詞查詢樹,Tire樹,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計,排序和儲存大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。它的優點是:利用字串的公共字首來減少查詢時間,最大限度地減少無謂的字串比較,查詢效率比雜湊樹高。
因為之前做過搜尋引擎,一直也對這塊很有興趣,所以對它底層知識的補充對個人而言,感覺深度有增加。
養成評估時空開銷的習慣
我刷leetcode必看官方解答裡估算的時間和空間複雜度。這也是作為一個架構師的必備基本能力。
陣列、雜湊這些因為資料的位置不需要進行查詢,只需要算數計算就可以得到,所以它們的時間複雜度是O(1)。
連結串列如果直接在頭部或者尾部插入,因為不需要查詢,所以時間複雜度也是O(1),但是定位的話因為涉及查詢,按遍歷查詢來算是log(n)。所以對於jdk1.7之前,hashmap底層採用的是陣列+連結串列的資料結構。所以如果不算雜湊衝突和擴容的話,獲取和插入資料的時間複雜度是O(1);如果出現了雜湊衝突,則插入因為是頭部插入,時間複雜度還是O(1);獲取時間複雜度因為涉及先查詢,所以是O(n),這個n代表衝突的數量。
對於在有序資料中進行查詢,因為可採用二分查詢等優化,時間複雜度可降到log(n).
對於遞迴呼叫,如果遞迴方法內進行2次呼叫。對於層數n來說,時間複雜度是2的n次方。舉個例子就是一個數等於前面兩個數之和。當然,如果是前面3個數之和,不進行優化的情況下時間複雜度就是3的n次方。
對於一個n*m的二維陣列等需要進行巢狀迴圈遍歷的,時間複雜度是O(n*m),有個特殊情況是n*m,這時候時間複雜度是n的平方。
對於全排列的情況,時間複雜度是O(n!)。
程式碼簡化的方法
我習慣的一種學習方法是先做題,有了一定自己的總結和思考之後,再看書學習別人的總結思考方法。對於刷leetcode相關性高,也比較受認可的書是《Cracking the Coding interview(6th)》,中文版翻譯是《程式設計師面試金典》。這本書對於面試官和麵試者來說讀了都會有一定的收穫。
我讀了這本書,對我印象最深的是介紹了兩種程式碼優化的方法:BUD和BCR。
BUD
BUD是瓶頸、不必要工作、重複工作 三個片語首字母的縮寫。
作者提出拿到一道程式設計題,可先嚐試用暴力解法將題目寫出來,之後找到解法的效能瓶頸,針對瓶頸進行優化,之後在去掉不必要的工作,最後去掉重複的工作。
這個經典的程式設計優化方法不只可應用於程式設計,還可應用於整個程式的優化,也是最常規的優化方法。
BCR
BCR是Best Conceivable Runtime的縮寫,意思是想知道自己可以優化到什麼程度,先估算可達到的最優情況。
比如:在一個無序陣列中,查詢兩個兩個相同的數。直覺來說如果找到這兩個數,最起碼需要將每個數都遍歷一遍,所以可達到的最優情況是O(n),無論怎麼優化,都不可能比這個更好。所以這就是優化的上限。
這本書裡還介紹了其他的優化方法如:使用額外資料結構、通過構建測試用例、根據題目的限制和提示來尋找線索,大家看這本書的時候可以瞭解下。