學演算法要讀《演算法導論》嗎?

京东云开发者發表於2024-03-27

這篇文章是我學習演算法的心得,希望它能夠給一些將要學習演算法且準備要讀大部頭演算法書籍的朋友一些參考,節省一些時間,也為了給經典的“黑皮書”祛魅,我覺得這些書籍在大部分網際網路從業者心中已經不再是進步的階梯,而是恐懼的陰影了,因為當一些學習路線中列出這些書目時,評論區多是調侃少是交流和討論。在這之前我也這些書抱有讀起來很困難的看法,但是在我參考過《演算法導論》之後,我覺得它更像是一杯“雞尾酒”:正文學習起來相對容易,能幫大家建立基礎,後續的習題和實驗,能幫助有需要的人進行深入學習,擴充套件的高階資料結構和數論等章節也能進行探索,就看大家怎麼來利用了。

開始學習演算法的契機是23年初參加《Hello 演算法》開源專案的內容貢獻,發現自己演算法基礎知識匱乏,索性準備系統地學習一下演算法相關的知識,在這前後一共讀了4本書:《Hello 演算法》、《資料結構與演算法之美》、《演算法(第四版)》和《演算法導論》(參考了前16章),學習期間在朋友的建議下實踐了艾賓浩斯學習法,覺得收貨良多。所以,本文會分兩部分,分別介紹演算法的學習指南和學習方法,希望對大家能有啟發:

演算法學習指南

我採用的專題閱讀學習,以《演算法》為主要參考書目,逐章閱讀,每學習完一個章節都會再去閱讀其他書籍的對應章節作為內容補充,並結合章後的習題練習(我覺得沒有練習的演算法學習都是空架子,因為大多時候看會了很可能還是寫不出來,但是官方給出的參考答案補全,可以參考《演算法(第四版)》參考答案開源專案)。但是事實上並不是這些書中所有的內容都值得參考,所以可以參照下面的學習方法:

《演算法》的第二章排序介紹了時間複雜度為O(n^2)和O(logn)的排序演算法,它並沒有直接介紹時間複雜度為O(n)的桶排序、計數排序和基數排序,而是將它們放在了第五章的字串排序中,我認為這部分並不好,所以在完成這一章的學習後,需要參考《Hello 演算法》的第十一章或者《演算法導論》的第八章,我認為參考前者更合適一些。

《演算法》的第三章在介紹紅黑樹時,它寫的是左傾紅黑樹(與2-3查詢樹同構),該資料結構是這本書的作者先前發表的一篇論文,它是經典紅黑樹的變體,實現相對容易。不過,在Java語言中TreeMap的實現採用的經典紅黑樹(與2-3-4查詢樹同構),我認為如果要擴充套件學習經典紅黑樹的話需要結合《演算法導論》的第十三章和TreeMap的原始碼,除此之外,暫時沒有發現參考學習經典紅黑書更合適的材料。

除此之外,《演算法》中沒有對動態規劃和貪心演算法的介紹,這一部分在《演算法導論》的第十五章和第十六章有講解,不過動態規劃和貪心演算法類的Leetcode題目在我看來還是比較難的,需要結合大量的練習才行。

以上,對於 基礎的演算法學習 就比較全面了,下面我們來討論一些問題作為補充:

《演算法導論》需要讀嗎?

我認為《演算法導論》真的是非常合適的演算法學習參考書,由於之前我也帶著“黑皮書”讀起來比較困難的想法,所以只把它作為了補充閱讀,沒有以它的內容為準,如果現在讓我重新選擇,我會把它作為主要參考書而其他作為補充閱讀。

《演算法導論》它不侷限於語言,其中的程式碼內容是虛擬碼實現,所以任何語言的學習者都是合適的。而且,它會用單獨的章節來介紹演算法中常用的策略,如分治法等,此外在資料結構中建立哨兵節點的技巧也在連結串列章節中也描述。我認為它的前十六章加上第二十二章用來學習基礎的演算法已經足夠了。開篇我說這本書像雞尾酒,因為 它還擴充套件了高階資料結構和更加深入的演算法知識,如斐波那契堆、van Emde Boas 樹、數論演算法和NP相關的知識等,所以,它的知識更加全面,面向的讀者範圍更廣。我認為作為普通的演算法學習者,一定要把握好學習的度,因為演算法本身相對更加耗費腦力和時間,鑽牛角尖式的學習在工作和生活間協調起來是不容易的,而且在演算法導論中確實有一些複雜的證明和推導存在,可以選擇性的跳過,因為我們的學習並非研究和探索,這樣降低了難度也提高了學習效率。

《Hello 演算法》是怎樣的一本參考書?

《Hello演算法》是一本基礎的演算法書,它的作者是也是Leetcode上劍指Offer系列題解的作者,這本書的知識基本上覆蓋了刷LeetCode所需要的知識,它在內容深度上沒有做擴充套件,像紅黑樹這些,也正如它的前言所述:它是一本能夠讓你避免讀大部頭便具備基本刷題能力的書,如果大家在短時間內想補足演算法知識的話,參考這本書足夠了,但是深入的學習是必要且無法被替代的。

對於只想刷題的同學該怎麼學習?

我覺得可以直接參考高頻題目的題單 分類 先刷起來,然後根據題目,發現缺少的知識進行補足。這樣相對更加高效,因為Leetcode具有技巧性和規律性,結合大量的題目練習是最好的方式,反而如果先啃完大部頭再回過頭刷題可能效率不夠高,而且這樣也不能得到預期的收益,因為這些書它並不是教你如何刷題的。


以上內容對於找到適合自己的演算法學習路線我認為已經足夠了,接下來是我在演算法學習中實踐過的學習方法:

艾賓浩斯學習法

我認為學習某項技能,不僅侷限於演算法的學習,最終目的在於形成對它的長期記憶,並不是僅僅保留印象,而形成長期記憶的方法也非常簡單:即頻繁而有效的重複刺激,像我們的母語和一些生活習慣(刷牙、打扮和繫鞋帶等)之所以不會忘記是因為我們每天都在反覆的刺激大腦如何運用,乃至最後都形成了肌肉記憶。總之,學習結合規律的複習,並歸納總結,便可以克服遺忘,達到溫故知新的結果。

艾賓浩斯遺忘曲線,即人對於知識的遺忘速度遵循 "先快後慢" 的原則。學得的知識在一天後,如不抓緊複習,很快就只剩下原來的 25%,而隨著時間的推移,遺忘的速度會減慢,遺忘的數量也隨之減少。

如果想有效抵抗遺忘,最好的辦法就是進行規律的複習(每 5 分鐘、30分鐘、12小時、1天、2天、4天、7天、15天、1個月、3個月、6個月)。

艾賓浩斯遺忘曲線是大家都熟悉的概念,但是我幾乎沒有發現我的同學採用類似的學習方法。如果不是在朋友的推薦下,我也不會去改變自己的學習方式,在我實踐過之後,收穫很大,所以也分享給大家,下面是部分我用來記錄學習和複習的艾賓浩斯表格:

image.png

我並沒有完全照搬它的複習時間,而是採用了2小時、12小時、2天、7天、15天、1個月和3個月這樣的時間間隔,其中表格中記錄的是學習日期,綠色表示按時完成複習,紅色表示沒有按時複習。

採用這個學習方法我認為需要始終堅持 “循序漸進,按部就班” 的學習理念,不能一時圖快而在短時間內學習過多知識,否則它會帶來長時間的複習壓力,也不能採取斷斷續續學習幾天就休息一陣子的方式,而是真正地讓學習成為一種習慣,慢慢地積累達到知識穩步增長的目的,這更像是投資的複利。

這種學習方法完全打破了我之前“從來不復習,永遠看新的”的學習方式,而且不復習經常會帶來“這個東西我看過,但是我忘了”的困擾,導致最後學完什麼都沒有剩下的局面,並且從採用這個學習方法之後,以“手寫線段樹”為例,真得可以信手拈來,像“肌肉記憶”一樣,所以規律的學習和複習是很有必要的。需要注意的是:這種學習方式需要耐心、毅力和自制力的輔助,並根據自身記憶情況進行合理的調整,達到合適的學習和複習模式,否則很容易在遇到長假休息時導致學習計劃夭折。

Over

所有內容到這裡就已經結束了,文末是一些優秀的參考文章和題單,希望能幫助大家在演算法學習上少走一些彎路,最後祝大家學得開心~


巨人的肩膀

  • 《Hello 演算法》

  • 《演算法(第四版)》

  • 《演算法導論》

  • 《資料結構與演算法之美》

  • GitHub - algorithms-sedgewick-wayne

  • GitHub - LogicStack-LeetCode

  • Github - LeetCode題單

  • Leetcode - 論如何 4 個月高效刷滿 500 題並形成長期記憶

相關文章