斐波拉契数列加强版——时间复杂度O(1),空间复杂度O(1)

对于斐波拉契经典问题,我们都非常熟悉,通过递推公式F(n) = F(n - 1) + F(n - 2),我们可以在线性时间内求出第n项F(n),现在考虑斐波拉契的加强版,我们要求的项数n的范围为int范围内的非负整数,请设计一个高效算法,计算第n项F(n)。第一个斐波拉契数为F(0) = 1。 给定一个非负整数,请返回斐波拉契数列的第n项,为了防止溢出,请将结果Mod 1000000007。 

斐波拉契数列的计算是一个非常经典的问题,对于小规模的n,很容易用递归的方式来获取,对于稍微大一点的n,为了避免递归调用的开销,可以用动态规划的思想轻松获得,时间复杂度为O(n),空间复杂度为O(1). 但是对于更大规模,比如上题中的n的范围,动态规划所花的时间也不少了。好在之前在Code Hunt上碰倒这个问题。

考虑下面三个矩阵:

F(n)    F(n-1)        1,1         F(n-1)  F(n-2)

F(n-1) F(n-1)  与   1,0   与   F(n-2)  F(n-3)

分别设为S(n), M, S(n-1).  S(n) = M x S(n-1).

于是

S(n) = M^(n-1) x S(1) = M^n;   (关系1)

再来看看,若n为32位正整数,设c[32]为其二进制序列的逆序列, c[i] =0,1;

n = Σ(c[i]*2^i),  i=0,...,31;

所以只要我知道M的2^i 方幂(i=0,1,2,...,31),我们可以轻松计算出S(n)

而计算出32个M的幂需要做32次矩阵乘法,而计算M^n次方,即M^( Σ(c[i]*2^i) ) 也最多需要做32次矩阵乘法

因而最多64次矩阵乘法即可计算出任意32位正整数范围的n对应的S(n)

 1 class Fibonacci { 2  /*author: Haibin Chen*/
 3 public:
 4     int getNthNumber(int n) {
 5         // write code here
 6         if(n <=1) return 1;
 7         long a[32];
 8         long b[32];
 9         long c[32];
10         long d[32];
11         a[0]=1;
12         b[0]=1;
13         c[0]=1;
14         d[0]=0;
15         int i,j;
16         for(i=1;i<32;i++){
17             a[i] = a[i-1];
18             b[i] = b[i-1];
19             c[i] = c[i-1];
20             d[i] = d[i-1];
21             getMulti(a[i],b[i],c[i],d[i],a[i],b[i],c[i],d[i]);
22         }
23         long ra = 1,rb =0,rc=0,rd=1,mask=1;
24         for(i=0;i<32;i++){
25             if((n&mask)!=0){
26                getMulti(ra,rb,rc,rd,a[i],b[i],c[i],d[i]);
27             }
28             mask = mask <<1;
29         }
30         return ra;
31     }
32     void getMulti(long &a,long &b,long &c,long &d,long a1,long b1,long c1,long d1){
33         long tempa = (a*a1+b*c1)%1000000007;
34         long tempb = (a*b1+b*d1)%1000000007;
35         long tempc = (c*a1+d*c1)%1000000007;
36         long tempd = (c*b1+d*d1)%1000000007;
37         a = tempa;
38         b = tempb;
39         c = tempc;
40         d = tempd;
41     }
42 };
时间: 2024-10-12 21:54:26

斐波拉契数列加强版——时间复杂度O(1),空间复杂度O(1)的相关文章

斐波拉契数列、楼梯问题、奶牛问题

斐波拉契数列:波那契数列,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.34.--在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)[from 百度百科 http://baike.baidu.com/link?url=8LKtKTAllUGDMe610zIO0DAjS3CCeAOpXiCFvH_Y47_I_XDRgzyGcrzsodd1OHO726FJNPWkqzkQC7PIuGu_

斐波拉契数列的计算方法

面试题9.斐波拉契数列 题目: 输入整数n,求斐波拉契数列第n个数. 思路: 一.递归式算法: 利用f(n) = f(n-1) + f(n-2)的特性来进行递归,代码如下: 代码: long long Fib(unsigned int n) { if(n<=0) return 0; if(n==1) return 1; return Fib(n-1) + Fib(n-2); } 缺陷: 当n比较大时递归非常慢,因为递归过程中存在很多重复计算. 二.改进思路: 应该采用非递归算法,保存之前的计算结

斐波拉契数列的递归、非递归、公式法多种方法实现

实现斐波拉契数列:1,1,2,3,5,8...,当n>=3时,f(n)=f(n-1)+f(n-2). 解:求解斐波拉契数列方法很多,这里提供了4种实现方法和代码,由于第5种数学公式方法代码太过繁琐,只做简单介绍 方法一:递归调用,每次递归的时候有大量重复计算,效率低,可将其调用的过程转化成一颗二叉树进行分析,二叉树的总结点个数不超过(2^n-1)个,由于其是不完全二叉树,那么函数计算的次数必小于(2^n-1),时间复杂度为O(2^n):递归调用的深度为n,空间复杂度为O(n) 方法二:非递归数组

斐波拉契数列的快速求法

由斐波拉契数列的公式:f(n)=f(n-1)+f(n-2),如果使用递归方法,非常的简短易懂,但是重复计算太多,时间复杂度成指数形势增长. 由矩阵乘法可以得到: 又 于是有 剩下的就是计算矩阵的过程了. 斐波拉契数列的快速求法

剑指offer-第二章算法之斐波拉契数列(青蛙跳台阶)

递归与循环 递归:在一个函数的内部调用这个函数. 本质:把一个问题分解为两个,或者多个小问题(多个小问题相互重叠的部分,会存在重复的计算) 优点:简洁,易于实现. 缺点:时间和空间消耗严重,如果递归调用的层级太多,就会超出栈容量. 循环:通过设置计算的初始值及终止条件,在一个范围内重复运算. 斐波拉契数列 题目一:写一个函数,输入n,求斐波拉契(Fibonacci)数列的第n项,定义如下: 第一种解法:用递归的算法: long long Fabonacci(unsigned int n) { i

【动态规划专题】1:斐波拉契数列问题的递归和动态规划

<程序员代码面试指南--IT名企算法与数据结构题目最优解> 左程云 著 斐波拉契数列问题的递归和动态规划 [题目]:给定整数N,返回斐波拉契数列的第N项.补充问题1:给定整数N,代表台阶数,一次可以跨2个或者1个台阶,返回有多少种走法.补充问题2:假设农场中成熟的母牛每年只会生产1头小母牛,并且永远不会死.第一年农场只有1只成熟的母牛,从第2年开始,母牛开始生产小母牛.每只小母牛3年后成熟又可以生产小母牛.给定整数N,求出N年后牛的数量. [举例]斐波拉契数列f(0)=0, f(1)=1,f(

Fibonacci斐波拉契数列----------动态规划DP

n==10 20 30 40 50 46 体验一下,感受一下,运行时间 #include <stdio.h>int fib(int n){ if (n<=1)     return 1; else            return fib(n-1)+fib(n-2); }int main( ){ int n; scanf("%d",&n); printf("%d\n" ,fib(n) );} 先 n==10 20 30 40 50 46

青蛙跳台阶问题-斐波拉契数列

题目1:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级.求总共有多少种跳法 首先我们考虑最简单的情况,加入只有1级台阶,那显然只有一种跳法,如果有2级台阶,那就有两种跳的方法了:一种是分两次跳,每次跳1级:另外一种就是一次跳2级 现在我们来讨论一般情况.我们把n级台阶时的跳法看成是n的函数,记为f(n).当n>2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1):另外一种选择是第一次跳2级,此时跳法数目等于后面剩下的

浅谈C#中的斐波拉契数列

突然对那些有趣的数学类知识感兴趣了,然后就简单研究了一下斐波拉契数列,看看它的有趣之处! 斐波拉契数列(Fibonacci Sequence),又称黄金分割数列,该数列由意大利的数学家列奥纳多·斐波那契发现的.这种数列指的是这样一个数列:0.1.1.2.3.5.8.13.21. 34.--在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*). 用C#实现斐波拉契数列的代码: Console.Write("请输入一个长