從一個小例子來初步認識遞迴,迭代,動態規劃。
阿新 • • 發佈:2019-01-02
問題:有n步臺階,一次只能上1步或者2步,共有多少種走法?
思路:
a 遞迴
步驟1:找到走完前n步臺階和前n-1步臺階之間的關係。
為了走上n步臺階,只有兩種方法:從n-1步臺階爬1步走到或從n-2步臺階處爬兩步走到。如果f(n)是爬到第n臺階的方法數,則f(n) = f(n-1) + f(n -2)。這裡需要思考:n為2時等式是否成立,也就是使等式成立的n的範圍是多少?
f(1) = 1;
f(2) = 2;
步驟2:確保開始條件是正確的。
遞迴方法的時間複雜度是n的指數級,因為有很多冗餘的計算,如下:
f(5)
=f(4)+f(3)
=f(3)+f(2)+f(2)+f(1)
=f(2)+f(1)+f(2)+f(2)+f(1)
b 迭代
可以直接將遞迴轉換成迭代,感覺有點反過來的意思。可以類比高中學過的數列的有關遞推表示式的一些東西。
從這個問題的來看,迭代時間要比遞迴少。
c 動態規劃
動態規劃是解決下面這些性質類問題的技術:
1、一個問題可以通過更小問題的解決方法來解決級問題的最優解包含了其子問題的最優解,也就是最優子結構性質。
2、有些子問題的可能需要多次計算,即子問題的重疊的性質。
3、子問題的解儲存在一張表格裡,這樣每個子問題只用計算一次。
4、需要額外的空間以節省時間
爬臺階的問題完全符合上面所說的四條性質,可以用動態規劃來解決。
思路:
a 遞迴
步驟1:找到走完前n步臺階和前n-1步臺階之間的關係。
為了走上n步臺階,只有兩種方法:從n-1步臺階爬1步走到或從n-2步臺階處爬兩步走到。如果f(n)是爬到第n臺階的方法數,則f(n) = f(n-1) + f(n -2)。這裡需要思考:n為2時等式是否成立,也就是使等式成立的n的範圍是多少?
f(1) = 1;
f(2) = 2;
步驟2:確保開始條件是正確的。
int recursion(int n)
{
if (n <= 2)
return n;
else
return recursion(n - 1) + recursion(n - 2);
}
遞迴方法的時間複雜度是n的指數級,因為有很多冗餘的計算,如下:
f(5)
=f(4)+f(3)
=f(3)+f(2)+f(2)+f(1)
=f(2)+f(1)+f(2)+f(2)+f(1)
b 迭代
可以直接將遞迴轉換成迭代,感覺有點反過來的意思。可以類比高中學過的數列的有關遞推表示式的一些東西。
int iteration(int n) { if (n <= 2) return n; int first = 1, second = 2, third; for (int i = 3; i <= n; i++) { third = first + second; first = second; second = third; } return third; }
從這個問題的來看,迭代時間要比遞迴少。
c 動態規劃
動態規劃是解決下面這些性質類問題的技術:
1、一個問題可以通過更小問題的解決方法來解決級問題的最優解包含了其子問題的最優解,也就是最優子結構性質。
2、有些子問題的可能需要多次計算,即子問題的重疊的性質。
3、子問題的解儲存在一張表格裡,這樣每個子問題只用計算一次。
4、需要額外的空間以節省時間
爬臺階的問題完全符合上面所說的四條性質,可以用動態規劃來解決。
int dp(int n) { int *p = new int[100]; p[1] = 1; p[2] = 2; for (int i = 3; i <= n; i++) { p[i] = p[i - 1] + p[i - 2]; } return p[n]; }