《演算法圖解》讀書筆記
一、演算法簡介
這的確是一本像小說一樣有趣的演算法入門書,講的是一個事兒,一個理兒,沒有數學公式,不像《演算法設計與分析基礎》那樣是一本理論書。
這裡記錄的只是讀書過程中對重要結論和關鍵性質的記錄,關於各個演算法的精髓後續討論。
1.查詢演算法:二分查詢,用於有序元素列表(將執行步驟從40億減少到32個!)
2.大O表示法:
演算法執行時間的增速;指出了最糟情況下的執行時間
O(log n),對數時間,如二分查詢
O(n),線性時間,如簡單查詢
O(n*log n),如快速排序
O(n2),如選擇排序
O(n!),如旅行商問題的解決方案
演算法執行時間並不以秒為單位。
演算法的速度指的並非時間,而是運算元的增速。
談論演算法的速度時,我們說的是隨著輸入的增加,其執行時間將以什麼樣的速度增加。
O(log n)比O(n)快,當需要搜尋的元素越多時,快得越多。
二、選擇排序
1.陣列和連結串列的操作執行時間:
陣列 |
連結串列 |
|
讀取 |
O(1) |
O(n) |
插入 |
O(n) |
O(1) |
刪除 |
O(n) |
O(1) |
陣列:隨機訪問和順序訪問
連結串列:順序訪問
Facebook儲存使用者名稱,既不是資料也不是連結串列,而是混合結構:連結串列陣列。
2.選擇排序
遍歷列表,找出最多(大)的,將其新增到一個新列表中;
再次這樣做,找出第二多(大)的;
繼續這樣做,得到一個有序列表。
其執行時間是O(n2)。
3.總結
計算機記憶體由於一大堆抽屜。
陣列的元素都在一起。
連結串列的元素是分開的,其中每個元素都儲存了下一個元素的地址。
陣列的讀取速度很快。
連結串列的插入和刪除速度很快。
三、遞迴
每個遞迴函式有兩個條件:
基線條件:函式不再呼叫自己
遞迴條件:函式呼叫自己
所有函式呼叫都進入呼叫棧,呼叫另一個函式時,當前函式暫停並處於未完成狀態。
四、快速排序
分而治之(D&C):將問題逐步分解。
編寫涉及陣列的遞迴函式時,基線條件通常是陣列為空或只包含一個元素。
分土地問題:將一塊土地均勻地分成方塊,且分出的方塊儘可能大。
求和問題:給定一個數字陣列,求他們想加的結果。
快速排序方法:
1. 選擇基準值;
2. 將陣列分成兩個子陣列:一個由所有小於基準值的數字組成的子陣列和一個由所有大於基準值的數字組成的子陣列;
3. 對這兩個子陣列進行快速排序。
實現快速排序時,隨機地選擇用作基準值的元素。平均執行時間為O(n logn)。
五、散列表
六、廣度優先搜尋
七、迪克斯特拉演算法
八、貪婪演算法
貪婪演算法是一種非常簡單的問題解決策略,即每步都選擇區域性最優解,用於處理沒有快速演算法的問題。
1. 教室排程問題
2. 揹包問題
3. 集合覆蓋問題
4. 旅行商問題
從揹包問題可知,貪婪演算法並不一定得到全域性最優解,但非常接近。
近似演算法:速度快,且得到的近似解與最優解很接近。在有些情況下,完美是優秀的敵人。
NP完全問題:
以難解著稱,需要計算所有的解,並從中選出最小/最短的那個。
識別NP完全問題:
1. 元素較少時演算法執行速度非常快,但隨著元素數量的增加,速度變得非常慢。
2. 涉及“所有組合”的問題通常是NP完全問題。
3. 不能將問題分成小問題,必須考慮各種可能的情況。這可能是NP完全問題。
4. 如果問題涉及序列且難以解決,它可能是NP完全問題。
5. 如果問題涉及集合且難以解決,它可能是NP完全問題。
6. 如果問題可轉換為集合覆蓋問題或旅行商問題,那它肯定是NP完全問題。
九、動態規劃
揹包問題:
可通過集合子集或排列組合方式找出共有多少種商品組合。再找出價值最高的組合。
動態規劃:
工作原理是先解決子問題,再逐步解決大問題,可藉助前面子問題的結果。在揹包問題中,再增加一件商品時,最大值可能發生變化,但前面的子問題不受到影響。沿著表格的一列往下走,最大價值不會降低,因為每一個子問題(表格)儲存的都是當前最大價值,最不濟也是上面那個最大值。當行的排列順序發生變化時,不會影響最終結果,不會因為先看到吉他後看到電腦而影響最終揹包裡要裝的東西。在使用動態規劃時,沒法判斷該不該拿走商品的一部分,貪婪演算法可以。僅當每個子問題都是離散的,即不依賴於其它子問題時,動態規劃才管用。
最長公共子串:
如果兩個字母不同,值為0;如果兩個字母相同,值為左上角鄰居的值加1。
連續的。
最長公共子序列:
如果兩個字母不同,就選擇上方和左方鄰居中較大的那個;如果兩個字母相同,就將當前單元格的值設定為左上方單元格的值加1。
不一定連續。
費曼演算法:
(1) 將問題寫下來。
(2) 好好思考。
(3) 將答案寫下來。