求斐波那契数列的三种方法------递归法、for循环法、快速幂矩阵法

1 递归法求斐波那契数列,时间复杂度O(n^2),实现代码如下:
#include <iostream>
using namespace std;

int Fib(int n) {
if(n <= 2) return 1;
else {
return Fib(n-1) + Fib(n-2);
}

}
int main(){
int n, result;
cin >> n;
result = Fib(n);
cout << result;
return 0;
}
2 for循环法求斐波那契数列,时间复杂度O(n), 其实改进的方法并不复杂。
上述递归代码之所以慢是因为重复的计算太多,我们只要想办法避免重复计算就行了。比如我们可以把已经得到的数列中间项保存起来,如果下次需要计算的时候我们先查找一下,如果前面已经计算过就不用再重复计算了。 更简单的办法是从下往上计算,首先根据f(0)和f(1)算出f(2),再根据f(1)和f(2)算出f.(....依此类推就可以算出第n项了。很容易理解,这种.思路的时间复杂度是0(n)。实现代码如下:

#include <iostream>
using namespace std;

long long Fib(int n) {
int result[2] = {0, 1};
if(n < 2) {
return result[n];
}
long long fibone = 1;
long long fibtwo = 0;
long long fibN = 0;
for(int i = 2; i <= n; i++) {
fibN = fibone + fibtwo;
fibtwo = fibone;
fibone = fibN;
}
return fibN;
}
int main(){
long long n;
cin >> n;
cout << "第" << n << "项的斐波那契数为: " << Fib(n);
return 0;
}
3 快速幂法求斐波那契数列,时间复杂度O(logN)
(1)为什么要用快速幂?

例如:现在有一个题目让你求 ,你可能觉得很简单啊,来一个for循环,循环b-1次就行了。但是如果b非常大的情况下,那这个做法是非常低效的,时间复杂度大致为 O(b)。

当用快速幂之后,时间复杂度为O(logn)。

(2)数的快速幂

例如我们用快速幂求 。

将指数拆分能够得到如下的结果。 
学过进制转换看到11拆开的样子肯定会很眼熟,其实这里就是跟二进制有关。

11的二进制为1011 ,我们只需要把11的二进制代码中为1的位数对应的2^n累乘起来即可,如2^11=2^8*2^2*2,对应二进制数中的第0、1、3位(从右往左数)均为1,故把它们累乘起来即可得到2^11。

这样一来,我们求2^11就不需要算10次了,现在三次就够了。

实现代码如下:

// 利用快速幂求x^n
#include <iostream>
using namespace std;

int pow(int x, int n) {
int ans = 1, base = x; //base 为底数, ans为最后累乘的结果x^n
while(n != 0) {
if(n&1 != 0) {
ans *= base;
}
base *= base;
n >>= 1; // 等价于把n右移一位并吧结果赋给n
}
return ans;
}
int main(){
int x, n;
cout << "请输入底数:";
cin >> x;
cout << endl;
cout << "请输入指数:";
cin >> n;
cout << x << "^" << n << "=" << pow(x, n);
return 0;
}
(3)矩阵的快速幂

于是我们得到如下公式: 其中Fn则对应结果矩阵result[0][1]的值

利用矩阵的快速幂书写如下代码: 

//用矩阵快速幂求斐波那契数列
#include <iostream>
#include<cstring>
using namespace std;

struct Matrix { //定义矩阵结构体
int a[2][2];
};

Matrix muliMatrix(Matrix x, Matrix y) { //求两个矩阵相乘
Matrix result; //结果矩阵result
memset(result.a, 0, sizeof(result.a)); //将结果矩阵的元素全部初始化为0
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 2; j++) {
for(int k = 0; k < 2; k++){
result.a[i][j] += x.a[i][k] * y.a[k][j]; //矩阵的乘法
}
}
}
return result;
}

int matrixPow(int n) { //快速幂求斐波那契数列
Matrix res, c;
memset(res.a, 0, sizeof(res.a));
for(int i = 0; i < 2; i++) {
res.a[i][i] = 1; //将res初始化为单位矩阵,因为任何矩阵和单位矩阵相乘都是它本身
}
c.a[0][0] = 1; //构造斐波那契矩阵
c.a[0][1] = 1;
c.a[1][0] = 1;
c.a[1][1] = 0;

while(n) {
if(n&1 != 0){ //这里和求x^n的快速幂类似
res = muliMatrix(res, c);
}
c = muliMatrix(c, c);
n >>= 1; // 等价于把n右移一位并把结果赋给n即n=>>1
}
return res.a[0][1]; //由于斐波那契第n项Fn对应结果举证中res.a[0][1]的值
}

int main(){
int n;
cout << "请输入斐波那契数列的项数: ";
cin >> n;
cout << endl;
cout << "第" << n << "项斐波那契数列的值=" << matrixPow(n);
return 0;
}
 
————————————————
版权声明:本文为CSDN博主「忘记时间的小白」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wangjian530/java/article/details/103838927

原文地址:https://www.cnblogs.com/makai/p/12828195.html