编程之美斐波那契(Fibonacci)数列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编程之美斐波那契(Fibonacci)数列相关的知识,希望对你有一定的参考价值。

  斐波那契数列是一个非常美丽、和谐的数列,有人说它起源于一对繁殖力惊人、基因非常优秀的兔子,也有人说远古时期的鹦鹉就知道这个规律。

  每一个学理工科的学生都知道斐波那契数列,斐波那契数列由如下递推关系式定义:

    F(0)=0, F(1)=1, n>1时,F(n)=F(n-1)+F(n-2)。

  每一个上过算法课的同学都能用递归的方法求解斐波那契数列的第n+1项的值,即F(n)。

1 int Fibonacci(int n)
2 {
3     if (n <= 0) return 0; 
4     else if (n == 1) return 1; 
5     else return Fibonacci(n-1) + Fibonacci(n-2); 
6 }

   我们的问题是:有没有更加优化的解法?

分析与解法

   技术面试的一个常见问题是,对于一个常见的算法,能否进一步优化?这个时候,平时喜欢超越课本思考问题的同学,就有施展才华的机会了。

解法一:递推关系式的优化

  用一个数组存储所有已计算过的项。这样便可达到用空间换时间的目的。在这种情况下,时间复杂度为O(n),空间复杂度也为O(n)。

解法二:求通项公式

  如果我们知道一个数列的通项公式,使用公式来计算会更加容易。

  特征方程为:x2=x+1,有两个特征根x1,x2

  则通项为F(n)=Ax1n+Bx2n,其中A,B可以通过F(0)和F(1)计算出来。

  通过通项公式,我们可以在O(1)时间内求出F(n)。但公式中引入了无理数,所以不能保证结果的糖度。

解法三:分治策略

  存在2*2的矩阵A,使得:

    [Fn Fn-1] = [Fn-1, Fn-2]*A

  通过递推可以求得A={{1, 1}{1, 0}}

  且:[Fn Fn-1] = [Fn-1, Fn-2]*A = [Fn-2, Fn-3]*A2= ... = [F1, F0]*An-1

  剩下的问题就是求解矩阵A的方幂。

  参考代码如下:

技术分享
 1 #include <iostream>
 2 using namespace std; 
 3 
 4 typedef long long LL; 
 5 const int maxn = 2; 
 6 const int MOD = 100000007; 
 7 
 8 struct Matrix 
 9 {
10     LL m[maxn][maxn]; 
11 }; 
12 
13 Matrix A = {1, 1, 1, 0}; 
14 Matrix I = {1, 0, 0, 1}; 
15 
16 Matrix multi(Matrix a, Matrix b)
17 {
18     Matrix c; 
19     for (int i = 0; i < maxn; i++)
20     {
21         for (int j = 0; j < maxn; j++)
22         {
23             c.m[i][j] = 0; 
24             for (int k = 0; k < maxn; k++)
25             {
26                 c.m[i][j] += a.m[i][k] * b.m[k][j] % MOD; 
27             }
28             c.m[i][j] %= MOD; 
29         }
30     }
31     return c; 
32 }
33 
34 Matrix power(Matrix A, int k)
35 {
36     Matrix ans = I, p = A; 
37     while (k)
38     {
39         if (k & 1)
40         {
41             ans = multi(ans, p); 
42             k--; 
43         }
44         k >>= 1; 
45         p = multi(p, p); 
46     }
47     return ans; 
48 }
49 
50 int main(int argc, char *argv[])
51 {
52     int n; 
53     while (cin >> n)
54     {
55         if (n <= 0) 
56         {
57             cout << 0 << endl;
58             continue; 
59         }
60         Matrix ans = power(A, n-1); 
61         cout << ans.m[0][0] << endl;
62     }
63 }
View Code

扩展问题

假设A(0)=1,A(1)=2,A(2)=2。对于n>2,都有A(k)=A(k-1)+A(k-2)+A(k-3)。

(1) 对于任何一个给定的n,如何计算A(n)?

(2) 对于n非常大的情况,如n=260的时候,如何计算A(n)modM(M<100000)呢?

 

以上是关于编程之美斐波那契(Fibonacci)数列的主要内容,如果未能解决你的问题,请参考以下文章

编程之美2.9 斐波那契数列

c语言编写计算斐波那契(Fibonacci)

常用算法——Fibonacci数列问题

斐波那契数列Fibonacci问题

斐波那契 [ Fibonacci] 数列之大整数求和

用递归方法计算斐波那契数列(Recursion Fibonacci Python)