【筆記】邁向人工智能 | 《算法圖解》:像小說一樣有趣的算法入門書
圖書簡介:算法導論 隨書代碼
推薦指數:★★★★☆
簡短書評:這本書非常適合有基本編程基礎(學過C或Python或任一門編程語言即可),而想入門算法的同學,圖文並茂,簡明易懂。書不厚,兩百頁左右,加上大量手繪示例圖,很快就翻完了,卻生動形象地介紹了基本的數據結構和算法,建議在看更專業的算法書之前,先過一下這本書。由於定位為入門,很多地方都只是簡單提了一下,並未深入探討,留待各位同學感興趣的話自學。書中案例以Python或偽代碼的形式呈現,就算不會編程語言,閱讀起來也沒什麽難度。學習編程或算法一定要杜絕眼高手低,建議親自敲敲書中的代碼,完成課後不多的作業,相信會有收獲。
第 1 章 算法簡介
“二分查找”:相比簡單順序查找,在有序的列表中應用該算法將會提升查找效率,特別是隨著列表增大的時候。
大O表示法:描述算法運行時間的增速(而非時間),指出了最糟情況下的運行時間,如O(log n)和O(n)。
第 2 章 選擇排序
數組:元素地址在內存中相鄰。讀取速度快,支持隨機訪問, O(1) 。插入(預留位置容易造成內存浪費和需要轉移)以及刪除元素不方便,O(n)。
鏈表:每個元素存儲下一個元素地址。同時讀取所有元素時,效率高,但如果需要跳躍,效率很低,O(n)。插入和刪除元素速度快,O(1)。
選擇排序:每次從剩下的元素中找出最大/下的元素,完成排序,時間復雜度為O(n2)。
第 3 章 遞歸
遞歸:在函數中調用函數本身。包含基線條件 (base case)和遞歸條件 (recursive case)。
遞歸條件指的是函數調用自己,而基線條件則指的是函數不再調用自己,從而避免形成無限循環。
調用棧:所有函數調用都進入調用棧,通過入棧和出棧完。調用棧可能很長(特別是在遞歸中),這將占用大量的內存,可以轉而使用循環或尾遞歸。
第 4 章 快速排序
分而治之(Divide and Conquer, D&C):一種著名的遞歸式問題解決方法,① 找出簡單的基線條件; ② 確定如何縮小問題的規模,使其符合基線條件。
快速排序:① 隨機選擇基準值;② 將數組分成兩個子數組:小於基準值的元素和大於基準值的元素;③ 對這兩個子數組進行快速排序;依此遞歸。
大O表示法:固定時間量c,通常不考慮,在相同時間復雜度情況下可能會有所影響。快速排序平均運行時間:O(nlog n),最糟情況為:O(n2)。
第 5 章 散列表
散列函數:總是將同樣的輸入映射到相同的索引,將不同的輸入映射到不同的索引。
散列表:一種數據結構(Key-Value),結合散列函數和數組,使用散列函數來確定元素的存儲位置。查找、插入和刪除速度都非常快,適用於模擬映射關系,防止重復,緩存。
沖突 :給兩個鍵分配的位置相同。簡單解決方法是:如果兩個鍵映射到了同一個位置,就在這個位置存儲一個鏈表。但如果散列表存儲的鏈表很長,散列表的速度將急劇下降。要避免沖突,散列函數需要有:較低的填裝因子(散列表包含元素數/位置總數,一旦填裝因子超過0.7,就該調整散列表的長度); 良好的散列函數(均勻映射)。
第 6 章 廣度優先搜索
圖:由節點 (node)和邊 (edge)組成,一個節點可能與眾多節點直接相連,這些節點被稱為鄰居。圖分有效圖/無效圖。
隊列:先進先出(FIFO);棧:先進後出(LIFO);
廣度優先搜索回答兩類問題。 第一類問題:從節點A出發,有前往節點B的路徑嗎? 第二類問題:從節點A出發,前往節點B的哪條路徑最短?
實現算法:① 創建一個隊列,用於存儲待檢查的對象;② 從隊列中彈出一個對象;③ 檢查這個對象是否滿足對象;④ 如果不是將這個對象的所有鄰居加入隊列;⑤ 回到第2步繼續執行,直至隊列為空或找到目標;(註意:檢查完一個對象後,應將其標記為已檢查,且不再檢查它。)
運行時間:O (V + E ),其中V 為頂點(vertice)數,E 為邊數。
第 7 章 狄克斯特拉算法
樹:一種特殊的圖,其中沒有往後指的邊。
狄克斯特拉算法:用於在加權圖中查找最短路徑,僅當權重為正時才管用,如果包含負權邊,可使用貝爾曼·福德算法。
實現算法:① 找出“最便宜”的節點,即可在最短時間內到達的節點;② 更新該節點的鄰居的開銷;③ 重復這個過程,直到對圖中的每個節點都這樣做;④ 計算最終路徑。
狄克斯特拉算法背後的關鍵理念:找出圖中最便宜的節點,並確保沒有到該節點的更便宜的路徑 !這種假設僅在沒有負權邊時才成立。
第 8 章 貪婪算法
集合:類似於列表,只是不能包含重復的元素,可執行並集、交集和差集操作。
貪婪算法:尋找局部最優解,企圖以這種方式獲得全局最優解。
NP完全問題:① 元素較少時算法的運行速度非常快,但隨著元素數量的增加,速度會變得非常慢;② 涉及“所有組合”的問題通常是NP完全問題;③ 不能將問題分成小問題,必須考慮各種可能的情況,這可能是NP完全問題;④ 如果問題涉及序列(如旅行商問題中的城市序列)且難以解決,它可能就是NP完全問題;⑤ 如果問題涉及集合(如廣播臺集合)且難以解決,它可能就是NP完全問題;⑥ 如果問題可轉換為集合覆蓋問題或旅行商問題,那它肯定是NP完全問題。
對於NP完全問題,還沒有找到快速解決方案,最佳的做法是使用近似算法(速度有多快;近似解與最優解的接近程度)。
第 9 章 動態規劃
動態規劃:給定約束條件下找到最優解,在問題可分解為彼此獨立且離散的子問題時,就可使用動態規劃來解決。
每種動態規劃解決方案都涉及網格,單元格的值就是要優化的值,每個單元格都是一個自問題,所以應該考慮如何將問題分成子問題,這有助於找出網格的坐標軸。
第 10 章 K最近鄰算法
KNN:用於分類和回歸,需要考慮最近的鄰居。分類就是編組(橙子還是柚子);回歸就是預測結果(如一個數字)。
特征抽取:意味著將物品(如水果或用戶)轉換為一系列可比較的數字,能否挑選合適的特征事關KNN算法的成敗(緊密相關,不偏不倚)。
距離計算:畢達哥拉斯公式,或余弦相似度。
第 11 章 接下來如何做
二叉查找數:對於其中的每個節點,左子節點的值都比它小,而右子節點的值都比它大。在二叉查找樹中查找節點時,平均運行時間為O(log n),但在最糟的情況下所需時間為O(n);相比有序數組,二叉查找數插入和刪除操作的速度要快得多,但也存在一些缺點,如不能隨機訪問。可了解B樹,紅黑樹,堆,伸展樹等內容。
反向索引 (inverted index):如一個散列表,將單詞映射到包含它的頁面,常用於創建搜索發動機。
傅裏葉變換:如果能夠將歌曲分解為不同的頻率,就可強化你關心的部分,如強化低音並隱藏高音。傅裏葉變換非常適合用於處理信號,可使用它來壓縮音樂。
並行算法:設計起來很難,要確保它們能夠正確地工作並實現期望的速度提升也很難。有一點是確定的,那就是速度的提升並非線性的,必須考慮到並行性管理開銷和負載均衡。
MapReduce:基於兩個簡單的理念——映射(map )函數和歸並(reduce )函數。
布隆過濾器:一種概率型數據結構 ,它提供的答案有可能不對,但很可能是正確的。使用散列表時,答案絕對可靠,而使用布隆過濾器時,答案卻是很可能是正確的。布隆過濾器的優點在於占用的存儲空間很少。HyperLogLog:近似地計算集合中不同的元素數,與布隆過濾器一樣,它不能給出準確的答案,但也八九不離十,而占用的內存空間卻少得多。
安全散列算法(secure hash algorithm,SHA)函數:給定一個字符串,SHA返回其散列值。SHA被廣泛用於計算密碼的散列值,這種散列算法是單向的。
局部敏感的散列算法:有時候,你希望結果相反,即希望散列函數是局部敏感的,需要檢查兩項內容的相似程度時,Simhash很有用。
Diffie-Hellman算法及其替代者RSA依然被廣泛使用。它使用兩個密鑰:公鑰和私鑰,來進行加解密。
線性規劃:用於在給定約束條件下最大限度地改善指定的指標。
【筆記】邁向人工智能 | 《算法圖解》:像小說一樣有趣的算法入門書