斐波那契數列大家都很熟悉了
f(n) = f(n-1) + f(n-2)
f(0) = 1
f(1) = 1
如果要用計算機程序來實現這個功能的話,根據上面的遞推公式很容易想到使用遞歸的方式,使用遞推的優點是程序員不用考慮具體的計算過程,只要找好遞推的明確出口就可以了。
int fib(int n)
{
if (n == 0 || n == 1) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
遞歸的缺點是涉及到函數調用的開銷,執行的效率比較低。
當然也可以使用迭代的方式進行求解,迭代從已知的問題的解出發不斷的去推導出未知問題的解,說簡單點,遞歸是一個自頂向下的過程,迭代是自底向上的過程。
int fib(int n)
{
int temp1 = 1;
int temp2 = 1;
for (int i = 2; i < n; i++) {
int temp = temp1 + temp2;
temp1 = temp2;
temp2 = temp;
}
return temp1 + temp2;
}
迭代的方法沒有自身調用的過程,因此效率要比遞歸高很多;、
我們再回頭看下遞歸的實現,如果要求解fib(5)就需要得到fib(4)和fib(3),求解fib(4)就需要得到fib(3)和fib(2),求解fib(3)就需要得到fib(2)和fib(1),求解fib(2)就需要得到fib(1)和fib(0)。同樣求解fib(3)也要經過這樣的過程,勢必會造成重複計算和重複的函數入棧和出棧。如果我們在計算過程中將已經求解出來的結果保存下來,然後在計算中直接使用這些結果,這樣會效率高很多。這個方法就是動態規劃。
int fib(int n, int *table)
{
if (table[n]) {
return table[n];
}
table[n] = fib(n - 1) + fib(n - 2);
return table[n];
}
int get_value(int n)
{
int *table = (int *)malloc(sizeof(int) * (n + 1));
table[0] = 1;
table[1] = 1;
return fib(n, table);
}