最近重新研讀了下《挑戰程序設計》對動態規劃和遞歸的關係有了點新的理解,之前的理解過於機械化,單純的以爲根據遞推公式可以直接寫DP代碼。
通俗的來說,
遞歸 是 考慮所有的情況,一般使用搜索(DFS /BFS)來實現。
在那些 可以轉換爲 DP 的遞歸算法中, 必定有很多重複的情況。
比如要做以下算術
1 + 1
1 + 1 + 1
2 + 1 + 1
3 + 1 + 1
那麼如果用遍歷思維,也是符合人類習慣的思維之一,我們會:
1+1=2
1 + 1 =2 ; 2+1 =3
2 + 1 =3 ; 3+1 =4 ;
3 + 1=4; 4+1 =5;
共 7次。
而如果我們聰明點的話,我們可以把一些已經計算的過程記錄下來
1+1 =2 => add[1][1]= 2
add[1][1] =2 ; 2 +1 =3 => add[2][1] =3
add[2][1]=3 ; 3+1 = 4 => add[3][1] =4;
add[3][1] =4; 4+1=5 => add[4] [1] =5 ;
共 4次運算。因爲add[][]是一個數字,可以直接返回。
可能 加法運算讓大家感覺不到優勢在哪裏, 如果 把 + 號 當作是一個 很複雜的運算, 那麼這種優化就十分有價值了。
這種優化方法 叫做 記憶化搜索 方法。
這種方法和 遞歸 剪枝 有本質的區別, 剪枝 法是把那些根本不可能的分枝去掉,而沒有 對 遍歷過程中存在的循環去掉,所以計算量等級上沒有變化。
使用了 記憶化搜索 優化的遞歸算法,其時間複雜度 和 轉換後的DP算法是一致的。
所以我們有以下定義成立:
一般可以使用記憶化搜索進行優化的遞歸算法,我們可以使用DP來進行優化。
至於如何公式化的,通用化的把 遞歸轉變爲 DP,還需要繼續理解理解。