求Fibonacci数的三种方法和时间复杂度解析

题目:

定义Fibonacci数列如下:

f(0)=1

f(1)=1

f(n)=f(n-1)+f(n-2), n>=2

输入n,用最快的方法求该数列的第n项。

解答一:

直接用公式写递归函数。很简单,很低效,就不写了。时间复杂度T(N) = T(N-1) + T(N-2); 也是f(n)本身,2^(n/2)<f(n)<2^n。

解答二:

用循环求,也很直接,效率很高了,时间复杂度是O(n)。

int f(int n)

{

if(n
<= 1)

return 1;

int f0=1,
f1=1;

for(int i=2;
i<=n; ++i)

{

int t=f0+f1;

f0=f1;

f1=t;

}

return f1;

}

解答三:

用矩阵求,时间复杂度O(log n),效率是最高的。

Fibonacci数列递推公式可以使用矩阵表达:

[f(n),f(n+1)]=[f(n-1),f(n)] * =[f(0),f(1)] *=[1,1]*,
n>=0

用G(n)表达该矩阵的n次方,规定G(0)为单位阵I。

那么

G(2n)=G(n)*G(n)

G(2n+1)=G(n)*G(n)*G(1)

写出递归函数【伪代码】,时间复杂度O(log n):

Matrix2x2 g(int n)

{

if(n<=0) return G(0);

if(n==1) return G(1);

Matrix2x2 t = f(n/2);

return t*t*G(n%2);

}

矩阵运算还是比较麻烦,比较耗时的,仔细研究G(n)的结构,容易发现G(n)可以表示为如下形式:

这可以很容易地用数学归纳法证明。就不赘述了。

也就是说可以用两个整数(x,y)来表示G(n)。

f(n)=[1 1]*=x+y

这样可以重新实现该递归函数【C++代码】:

void g(int n, int&
x, int& y)

{

if(n<=1)

{

x = 0;

y = 1;

}

else

{

int x1,
y1;

g(n/2, x1, y1);

x = x1*x1+y1*y1;

y = (2*x1+y1)*y1;

if(n
% 2)

{

int t
= x;

x = y;

y += t;

}

}

}

int f2(int n)

{

int x,
y;

g(n, x, y);

return x+y;

}

求Fibonacci数的三种方法和时间复杂度解析,布布扣,bubuko.com

时间: 2024-10-19 16:22:54

求Fibonacci数的三种方法和时间复杂度解析的相关文章

求最大公约数的三种方法

一.最大公约数与最小公倍数 最大公约数,属于数论所探究的内容. 最大公约数可以通过下面的三种方法求出来. 最小公倍数呢,它与最大公约数的乘机为所求数之积. 比如求  x,y的最大公约数和最小公倍数 记住这个公式: x*y=最小公倍数*最大公约数 二.求最大公约数的三种方法 ①辗转相除法 算法流程图 int measure(int x, int y) { int z = y; while(x%y!=0) { z = x%y; x = y; y = z; } return z; } 运行结果: ②辗

python实现fibonacci数列的三种方法

第一种:递归法 def fibo(n): if n < 3: return 1 return fibo(n-1) + fibo(n-2) print(fibo(6)) 第二种:循环 1 def fibo1(n): 2 a, b = 1, 1 3 for i in range(n): 4 a, b = b, a+b 5 return a 6 7 print(fibo1(6)) 第三种:生成器 1 def fibo2(n): 2 a, b = 1, 1 3 while n: 4 yield a 5

求字符串长度的三种方法

1.指针 #include<stdio.h> int strlen(char s[]) {     int len=0; while(*s++!='\0') {       len++; } return len; } int main() { char s[]="123456789"; printf("%d\n",strlen(s)); system("pause");    return 0; } 2.计数 #include<

求字符串长度函数实现的三种方法

/* Date: 10/03/19 12:49 Description: 求字符串长度函数实现的三种方法*/ #include<stdio.h> int strlen1(char *s);int strlen2(char *s);int strlen3(char *s); int main(void) { char str[]="The function to test my length."; printf("The length1 is:%d\n",

C语言编程 求两个数的平均值方法(三种方法)

第一种方法是最常见的average=(a + b) / 2这种方式,求两个数的平均值 第二种方法是当 a<b 时averag=a+(b-a)/2 这里着重介绍的是第三种方法 average=(a&b) + (a^b)>>1 推导过程如下a + b = (a&b) 2 + (a^b)) --->average=((a&b)2+(a^b))/2 ---->average=(a&b) + (a^b)>>1 eg:两个数为15和515二进制

查看登陆系统用户的信息的三种方法详解

查看登陆系统用户的信息的三种方法详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.who这个命令显示可以谁在登陆,但是这个有很多的花式玩法,这个命令超简单 语法:who [OPTION]... [ FILE | ARG1 ARG2 ] 1.参数:-u,显示闲置时间,若该用户在前一分钟之内有进行任何动作,将标示成"."号,如果该用户已超过24小时没有任何动作,则标示出"old"字符串. 例如: 2.参数:-m,此参数的效果和指定"a

三种方法求解约瑟夫环问题

约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,直到圆桌周围的人全部出列. 方法1:使用stl::list模拟环形链表,参考剑指offer 代码: #include <iostream> #include <list> using namespace std; int lastNumber(unsigned int n,un

求乘法逆元的几种方法

(数学渣,下面的文字可能有误,欢迎指教)乘法逆元的定义貌似是基于群给出的,比较简单地理解,可以说是倒数的概念的推广.记a的关于模p的逆元为a^-1,则a^-1满足aa^-1≡ 1(mod p) 加减乘与模运算的顺序交换不会影响结果,但是除法不行.有的题目要求结果mod一个大质数,如果原本的结果中有除法,比如除以a,那就可以乘以a的逆元替代. 在mod p的运算中,a存在乘法逆元当且仅当a与p互质.一般题目给的是一个大质数,所以只要a不是p的倍数,就以求乘法逆元. 目前了解到的求法有三种:1.扩展

mysql分表的三种方法

mysql分表的3种方法 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. 根据个人经验,mysql执行一个sql的过程如下:1,接收到sql;2,把sql放到排队队列中 ;3,执行sql;4,返回执行结果.在这个执行过程中最花时间在什么地方呢?第一,是排队等待的时间,第二,sql的执行时间.其实这二个是一回事,等待的同时,肯定有sql在执行.所以我们要缩短sql的执行