遞迴:把乙個問題 a 轉換乙個或多個子問題,我們把它們的集合叫做 b;a 的答案可以由 b 得到;對於一種確定的遞迴方法,從 b 的答案得到 a 的答案有且只有一種方法。
迭代:與遞迴的思想一樣,只是在實現層面不一樣。
動態規劃:與遞迴思想一樣,不同的是由 b 的答案得到 a 的答案可能有多種方法(可能),每次選擇一種最優的方法去推導出 a 的答案。
分冶:與遞迴思想不一樣,遞迴強調由 i 到 i+1 (或反過來)的推進,乙個問題到乙個緊密關聯(遞進關係)問題的轉換;而分冶強調問題的劃分,乙個問題分解為多個簡單的問題。
畫圖 1 以表示它們的不同。
圖1幾種演算法思想的不同
1.我們先來剖析遞迴和迭代的本質不同
下面給出乙個斐波那契數列的兩種解決方法:
//遞迴求解方法
int f(int i)
//迭代求解方法
int f(int i)
return f[i];
}
在遞迴方法中,f(i) 函式會遞迴呼叫 f(i-1) 和 f(i-2),f(i-1)會遞迴呼叫 f(i-2) 和 f(i-3)......直到碰到遞迴出口 f(1) 和 f(0)。
在迭代方法中,先由 f[0] 和 f[1] 求得 f[2],再由 f[2] 和 f[3] 求 f[4].......一直求到 f(i),這個過程沒有遞迴呼叫函式,但是和遞迴的思想是一致的,為了求 f(i) 或 f[i] 必需要要先求 i-1 和 i-2 問題的答案。只是實現的方法不一樣而已。遞迴採用了遞迴呼叫,而迭代採用了自底向上求解方法,由此次計算結果直接得到下乙個問題的答案。
很明顯可以看出這兩種方法哪乙個更優:遞迴方法由於兩個原因效率太低,一是遞迴深度可能會非常大,而遞迴呼叫函式會產生時間耗費(函式棧構建,銷毀)和空間耗費(函式棧需要放在棧記憶體裡面);二是存在極大的重複呼叫,為了求 f(i) 要先呼叫 f(i-1) 和 f(i-2),而在 f(i-1)裡面又會呼叫 f(i-2),越往下走,重複呼叫的次數會越來越多,f(1) 會被呼叫無數遍。
遞迴和迭代的本質區別在於:
對遞迴而言,在本問題(稱為 i 問題)一輪的求解中,它不知道 i - 1 問題是怎麼求解的,它只知道只知道如何由 i - 1 問題的答案得到自己的答案。
對迭代而言,在本問題(稱為 i 問題)一輪的求解中,它明確知道 i - 1 的問題是怎麼求解的(有多種手段,如可以直接儲存 i - 1 問題的答案,或者通過其它方法求解),並且還知道如何由 i - 1 問題的答案得到自己的答案。
我們一般要將遞迴求解方法轉換為迭代求解方法,以獲得更高的效能,這就意味著,在迭代求解中,需要處理多乙個細節,即,給出 i - 1 問題的求解方法。絕大多數情況下,我們直接儲存 i - 1 問題的答案來達到這一點。這也揭示了一點,迭代一般是從底向上的,如斐波那契數列求解的迭代從 0,1,2 開始求解,不斷向上求解,每求解乙個問題,它的 i - 1 問題的答案已經得出了,所以可以很自然的完成迭代過程。對應的遞迴的方向往往是確定的,只能是 i 問題到 i - 1 問題的方向,因為只存在要求 i 問題,要遞迴呼叫 i - 1 問題的處理過程,而反過來是不存在的。
有一種優化的遞迴結合了遞迴與迭代的方法,實際上可以稱為自頂向下的迭代或帶有記憶功能的遞迴:
const static int unknown = -1;
//結合迭代與遞迴結合的方法,也稱為自頂向下的迭代,或者有記憶功能的遞迴
int f(int i)
if(i == 0) t = f[0] = 0;
if(i == 1) t = f[1] = 1;
if(i > 1) t = f(i - 1) + f(i - 2); //遞迴求解
return f[i] = t; //快取結果
}
這個方法明顯減少了遞迴呼叫的次數,因為一旦某個問題的解快取了,那麼就不會再遞迴呼叫它的子問題的求解過程。
2.遞迴與動態規劃
動態規劃 迭代與遞迴
遞迴 好像相對高明,但其實效率而言遞迴並不是最佳方案。迭代 貌似複雜,其實效能更高效。分而治之 所謂動態規劃 就是通過遞迴,找出問題本質,並且給出乙個初步的解之後,再將其等效的轉換為迭代的形式。兩個栗子 1.斐波那契數列 青蛙跳台階 2.最長公共子串行 對序列a 0,n b 0,m lcs a,b ...
DP動態規劃 遞迴迭代
在刷leetcode的時候,因為對dp和遞迴不是很熟,對兩者界限也很模糊。所以看了一些概念以後來寫乙個日記 這是一類問題的定義,解決這類問題的核心在於找到遞推公式 f x f x 1 g n 得到遞推公式之後,如何計算遞推公式存在兩種方法 自頂向下和自底向上 自頂向下 能採用遞迴實現 int fib...
整數劃分問題 動態規劃 遞迴
將乙個整數 n 劃分為 不超過m 組 的劃分數 如 n 4m 3 輸出 4 思路 使用動態規劃 定義狀態 dp i j j的i劃分的組數 遞推 dp i j dp i j i dp i 1 j 當m n時,變成了常見的整數劃分問題 cpp view plain copy include includ...