斐波那契數列如下:
1,2,3,5,8,13,21,34,……
如果設F(n)為該數列的第n項(n∈N*),那么這句話可以寫成如下形式:
F(n)=F(n-1)+F(n-2)
通項公式如下:
遞歸實現:
直接按照遞推公式實現,
由通項公式可以得到:當n趨近於無窮大時
由於T(n)≥F(n),這是一個指數階的算法
如果我們今年計算出了F(100),那么明年才能算出F(101),
爆炸增量函數是算法設計的噩夢。
1 int fib(int n) 2 { 3 if( n < 1) 4 return -1; 5 if( n == 1 || n == 2) 6 return 1; 7 return fib( n-1) + fib( n-2); 8 }
數組優化:
既然斐波那契數列中的每一項是前兩項之和,如果記錄前兩項的值,只需
要一次加法運算就可以得到當前項,那么可以使用數組。復雜度為O(n)。
1 int fib( int n) 2 { 3 if( n < 1) 4 return -1; 5 int *a = new int [n]; 6 a[1] = a[2] = 1; 7 for( int i = 3; i <= n; i++) 8 a[i] = a[i-1]+a[i-2]; 9 return a[n]; 10 }
迭代法:
其實只需要得到第n個斐波那契數,中間結果只是為了下一次使用,不需要
記錄,因此可以采用迭代法進行設計。使用若干輔助變量,迭代輾轉相
加,每次記錄前一項,時間復雜度為O(n),空間復雜度降到O(1)。
1 int fib( int n) 2 { 3 int i, s1, s2; 4 if( n < 1) 5 return -1; 6 if( n == 1 || n == 2) 7 return 1; 8 s1 = s2 = 1; 9 for( i = 3; i <= n; i++) 10 { 11 s2 = s1+s2; 12 s1 = s2-s1; 13 } 14 return s2; 15 }
對數階:
實質上,斐波那契數列時間復雜度還可以進一步降低到對數階O(logn)。
我們每次遞歸都將a+b的值賦給a,把a的值賦給b,通過觀察可以發現,從1和
0開始將規則反復應用n次,將產生一對數fib(n)和fib(n+1),
現在將這種規則看成a = bq + aq + a*pb = bp + aq,其中p=0,q=1。把這種變
換稱為T變換,Tpq 變換有個特性是 :
Tpq 的二次方等於Tp'q', p' = pp + qq'q' = 2pq + q*q。
即:a = (bp+aq)p+(bq+aq+ap)q+(bq+aq+ap)p
= b(2pq+q^2)+a(p^2+2pq+2q^2)
b = (bp+aq)p+(bq+aq+ap)q = b(p^2+q^2)+a(q^2+2pq)
此處p=0,q=1
1 int fib_iter( int a, int b, int count) 2 { 3 if( count == 0) 4 return b; 5 return fib_iter( a+b, a, count-1); 6 } 7 int fib( int n) 8 { 9 return fib_iter( 1, 0, n); 10 }