【编程之美】斐波那契(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 }

扩展问题

假设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)呢?

时间: 2024-11-22 16:46:02

【编程之美】斐波那契(Fibonacci)数列的相关文章

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

编程之美 2.9 斐波那契(Fibonacci)数列 斐波那契的递归表达式如下 F(n)=F(n-1)+F(n-2) n>=2 F(1)=1 F(0)=0 书中提到了三中解决方法 第一种:直接运用递归的方法来进行求解 package org.wrh.programbeautiful; import java.util.Scanner; public class Topic2_9 { public static void main(String[] args) { Topic2_9 t=new T

9.求斐波那契Fibonacci数列通项

(1)递归实现: #include<iostream>using namespace std;int Fibonacci(int); int main(){    int n;    cout<<"please input an number n: "<<endl;    cin>>n; for(int i=1;i<=n;i++)    {        cout<<Fibonacci(i)<<endl; 

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

之前做到一题, 不过由于Honor Code的缘故就不说是啥了, 很多人都知道 (-_-) 大概是说有n个牌,每个牌只有A,B两种状态. 当出现连续3个牌的状态一样时,认为不完美. 给出一个[1, 10000]的整数, 让求出完美的排列个数 那么我们就可以分析一下: /*-------------------------------------------------------------------------------分析:    首先要求出不美观的个数,但是尝试可以发现美观的排列更容易

【C语言】求斐波那契(Fibonacci)数列通项(递归法、非递归法)

意大利的数学家列昂那多·斐波那契在1202年研究兔子产崽问题时发现了此数列.设一对大兔子每月生一对小兔子,每对新生兔在出生一个月后又下崽,假若兔子都不死亡.   问:一对兔子,一年能繁殖成多少对兔子?题中本质上有两类兔子:一类是能生殖的兔子,简称为大兔子:新生的兔子不能生殖,简称为小兔子:小兔子一个月就长成大兔子.求的是大兔子与小兔子的总和. 月     份  ⅠⅡ  Ⅲ  Ⅳ  Ⅴ Ⅵ  Ⅶ  Ⅷ Ⅸ Ⅹ  Ⅺ  Ⅻ大兔对数 1  1   2   3   5  8  13  21 34 55 

斐波那契 (Fibonacci)数列

尾递归会将本次方法的结果计算出来,直接传递给下个方法.效率很快. 一般的递归,在本次方法结果还没出来的时候,就调用了下次的递归, 而程序就要将部分的结果保存在内存中,直到后面的方法结束,再返回来计算.如果递归比较大,可能会照成内存溢出. 实践证明,尾递归 ,确实比普通递归效率高. 下面的例子 ,用 普通递归需要10s完成 , 而用尾递归,只用了1s不到 package com.zf.dg; /** * 题目 * 有一种母牛,出生后第三年,开始生育,每年都生一头 母牛(貌似单性生育,这里就没公牛什

如何用Python输出一个斐波那契Fibonacci数列

a,b = 0, 1 while b<100: print (b), a, b = b, a+b 原文地址:https://www.cnblogs.com/apollo1616/p/9776116.html

HDU2842之斐波那契亚数列变形,动态规划

1.原题展示: 一根棒子上有n个环(n<=10^9) 第一个环可以随意取下或者放上 如果前k个环都不在棒子上,且第k+1个环在棒子上,则你可以取下或放上第k+2个环 给出n,求最少需要多少步可以取完棒子上的环? 2.思路分析: 如果要把n个环全部拿完,那么我们必须先拿完前n-2个环(只有这样才能拿走第n个环),剩下第n-1个环未拿走.当拿走前n-2个环所花的步骤数目为f(n-2)加上最后一个环,那么所花步数为f(n-2)+1步.对于第n-1个球,如果要拿走它,必须补上前n-2个球,放进去n-2个

ACM/ICPC算法训练 之 数学很重要—斐波拉契●卢卡斯数列(HNNUOJ 11589)

看到这个标题,貌似很高大上的样子= =,其实这个也是大家熟悉的东西,先给大家科普一下斐波拉契数列. 斐波拉契数列 又称黄金分割数列,指的是这样一个数列: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*) 在现代物理.准晶体结构.化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963起出版了以<斐波纳契数列季刊>为名的一份数学杂志,用于专门刊载这方面的

编程题目: 斐波那契以及台阶问题

0  n = 1 f(n)  =   1    n = 1 f(n-1) + f(n-2) n >=2 一.斐波那契 1.递归实现 递归实现的代码一目了然,简单易懂.但重复计算了元素,所以效率比较低下. 1 #!/usr/bin/env python3 2 3 def fibs(n): 4 if n < 0: 5 raise ValueError("n must >= 0") 6 if n == 0 or n == 1: return 1 7 else: 8 retu