斐波那契数列

0 递归

斐波那契数列定义:

 $F(n)=\left\{\begin{matrix}
0, & n=0\\
1, & n=1\\
F(n-1)+F(n-2), & n>1
\end{matrix}\right.$

递归解法最直观,但是复杂度也最高:$O(2^n)$

1 int Fibonacci(int n)
2 {
3     if (n <= 0) //细节可以处理非法输入
4         return 0;
5     else if (1 == n)
6         return 1;
7     return Fibonacci(n - 1) + Fibonacci(n - 2);
8 }
View Code

为了避免重复计算,可以将每一步计算得到的$F(i)$存起来,这样的话时间复杂度降为$O(n)$,但空间复杂度升为$O(n)$。

1 通项

 求解通项的方法有好几种,下面展示一种用线性代数求解的方法:

对于线性递推数列,通项公式可以表示为$F(n)=C_1\lambda_1^n+C_2\lambda_2^n$。

根据斐波那契数列的递推公式,可得其特征方程:

$x^2=x+1$

解之得特征值:$\lambda_1=\frac{1+\sqrt5}{2},\lambda_2=\frac{1-\sqrt5}{2}$

将特征值带入$F(0), F(1)$,解得$C_1=-\frac{1}{\sqrt5}, C_2=\frac{1}{\sqrt5}$

故斐波那契数列的通项公式为:
$F(n)=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n]$

用公式求解的复杂度为$O(1)$,但是由于无理数在计算机中的存储不是精确的,所以结果的精度很难保证。

2 分治

通过矩阵形式的递推:

$$\begin{bmatrix}
F(n)\\
F(n-1)
\end{bmatrix}=\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}\begin{bmatrix}
F(n-1)\\
F(n-2)
\end{bmatrix}$$

不断向下递推,可以得到:

$$\begin{bmatrix}
F(n)\\
F(n-1)
\end{bmatrix}={\begin{bmatrix}
1 & 1\\
1 & 0
\end{bmatrix}}^{n-1}\begin{bmatrix}
F(1)\\
F(0)
\end{bmatrix}$$

接下来就是求解矩阵的高次方,通过快速幂(https://baike.baidu.com/item/快速幂/5500243?fr=aladdin)可以在$O(logn)$时间内进行计算:
整数的快速幂代码:

 1 int QuickPow(int a,int n)
 2 {
 3     int ans = 1;
 4     while (n)
 5     {
 6         if (n & 1)
 7             ans *= a;
 8         a *= a;
 9         n >>= 1;
10     }
11 
12     return ans;
13 }
View Code

将传入的参数改为矩阵,乘法改为矩阵乘法,就可以得到矩阵快速幂:

以二阶矩阵为例,求解斐波那契数列:

 1 #define _CRT_SECURE_NO_WARNINGS
 2 
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 struct Matrix {
 8     int a[2][2];
 9 }base,ans;
10 
11 Matrix multi(Matrix a, Matrix b)
12 {
13     Matrix res;
14     for (int i = 0; i < 2; i++) //第i行
15     {
16         for (int j = 0; j < 2; j++)  //第j列
17         {
18             res.a[i][j] = 0;
19             for (int k = 0; k < 2; k++)
20                 res.a[i][j] += a.a[i][k] * b.a[k][j];
21         }
22     }
23 
24     return res;
25 }
26 
27 Matrix QuickPow(int n)
28 {
29     base.a[0][0] = base.a[0][1] = base.a[1][0] = 1;
30     base.a[1][1] = 0;   //初始化矩阵
31 
32     //结果矩阵初始化为单位阵
33     ans.a[0][0] = ans.a[1][1] = 1;
34     ans.a[1][0] = ans.a[0][1] = 0;
35 
36     while (n)
37     {
38         if (n & 1)
39         {
40             ans = multi(ans, base);
41         }
42         base = multi(base, base);
43         n >>= 1;
44     }
45 
46     return ans;
47 }
48 
49 int main()
50 {
51     int n;
52     cin >> n;
53 
54     QuickPow(n);
55     cout << ans.a[1][0] << endl;
56 
57     return 0;
58 }
View Code

 参考:https://www.zhihu.com/question/28062458/answer/39763094

转载于:https://www.cnblogs.com/EIMadrigal/p/11478906.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值