编程之美 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 Topic2_9();
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        long time1=System.currentTimeMillis();
        System.out.println("fibonacci数列中的第"+n+"个数为:"+t.fibonacci(n));
        System.out.println("计算s所需的时间"+(System.currentTimeMillis()-time1));
    }
    public int fibonacci(int n){
        if(n<=0){
            return 0;
        }
        else if(n==1){
            return 1;

        }
        else return fibonacci(n-1)+fibonacci(n-2);

    }

}

这种方法的时间复杂度为:O(2^n)

由于这种方法在计算中存在大量的重复计算,因此,我们可以对计算过的F(n)进行一个记录,当下次需要计算此值时,直接拿出来用就好,这样就可以减少一定的时间复杂度,这就是我们常见的用“空间来换取时间”的方法。

实现代码如下:

package org.wrh.programbeautiful;

import java.util.Arrays;
import java.util.Scanner;

public class Topic2_9 {

    int[] arr;
    public Topic2_9(int n){
        arr=new int[n+1];

    }
    public static void main(String[] args) {
        //Topic2_9 t=new Topic2_9();
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        Topic2_9 t=new Topic2_9(n);
        long time1=System.currentTimeMillis();
        System.out.println("fibonacci数列中的第"+n+"个数为:"+t.fibonacci(n));
        System.out.println("计算s所需的时间:  "+(System.currentTimeMillis()-time1));
        System.out.println(Arrays.toString(t.arr));
    }

    public int fibonacci(int n){
        if(arr[n]!=0){//如果数据已经被计算过了,则直接返回即可
            return arr[n];
        }
        else{
            if(n<=0){
                return 0;
            }
            else if(n==1){
                arr[n]=1;
                return 1;

            }
            else {
                arr[n]= fibonacci(n-1)+fibonacci(n-2);
                return arr[n];
            }
        }

    }
//  public int fibonacci(int n){
//      if(n<=0){
//          return 0;
//      }
//      else if(n==1){
//          return 1;
//
//      }
//      else return fibonacci(n-1)+fibonacci(n-2);
//
//  }

}

上面注释掉的代码为没有引入“空间”来进行数据的保存的代码。

==========================================

  • 第二种:求出通项表达式进行求解(根据信号系统的知识)

    由于斐波那契的递归表达式为:F(n)=F(n-1)+F(n-2),可知其特征方程为:

    x^2+x=1;解得特征值为:x1=(1+sqrt(5))/2,x2=(1+sqrt(5))/2;于是可得其通解,最后根据初始值求得其参数即可求得F(n)关于n的表达式,因此,我们就可以在时间复杂度为O(1)的时间内求出F(n)

    但是当n较大的时候,所花费的时间还是巨大的,因此下面简单的介绍关于一个数的n次方的求法:二分求幂

/*一个数的二分求幂的思想如下:求a^n(a的n次方) 如果n是偶数(即n%2==0) 则原来的等价于(a*a)^(n/2) , 如果是奇数则 求 a^(n-1) * a (此时n-1就变成了偶数了)。所以实现代码如下*/:

 power_n(int a , int n)
{
      if(n==0)
          return 1 ;
     else if(n==1)
         return a ;
     else if(n%2 == 0)
        return power_n(a*a , n>>1) ;
     else
        return a*power_n(a , n-1) ;
}
也可以用while实现:可以理解为将n幂级数展开了,循环第i次就利用了第i阶幂级数的系数。
long pow1_n(int a,int n)
{
    long d=1,t=a;
    while(n>0)
    {
        if(n%2==1)
            d=(d*t);
        n>>=1;
        t=t*t ;
    }
    return d;
}
这里的2分都用到了移位操作大大加快了速度。那么对于很多次数的幂运算就可以用二分幂运算去计算了复杂度为logn。

===============================================

  • 第三种:分治策略进行求解(书上讲解的比较清晰)

就是利用了[F(n),F(n-1)]=[F(n-1),F(n-2)]*A;其中A为一个2*2的矩阵,

这样一个表达式,而得出了

[F(n),F(n-1)]=[F(1),F(0)]*(A^(n-1)),即求F(n)转换为了求矩阵A的

次幂,因此,实现代码与上面是类似的。

这个里面涉及到二阶矩阵乘法的运算,直接利用矩阵乘法的定义还是比较好实现的。如果涉及到高阶矩阵的乘法,则就应采用分块矩阵的乘法来进行解决了,在算法导论这本书上有详细的讲解,这里不再介绍

时间: 2024-10-25 16:52:10

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

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)数列

斐波那契数列是一个非常美丽.和谐的数列,有人说它起源于一对繁殖力惊人.基因非常优秀的兔子,也有人说远古时期的鹦鹉就知道这个规律. 每一个学理工科的学生都知道斐波那契数列,斐波那契数列由如下递推关系式定义: 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 (

斐波那契 [ 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起出版了以<斐波纳契数列季刊>为名的一份数学杂志,用于专门刊载这方面的

编程之美2.9 斐波那契数列

斐波那契数列是我们在学习C语言的时候.在递归那一章的经典实例.当然,还会有汉诺塔的样例. 这个问题时这样定义的: 0 (x <= 0) f(x)   =  1 (x == 1) f(x - 1) + f(x - 2) (x > 1) 看到这个递推公式后.我们非常easy能够写出例如以下的代码: 函数声明: typedef long long ll; ll DutFibonacci_1(int); 函数定义: /*经典的斐波那契数列的递归解法,并且每一个人都知道这样的方法效率非常低*/ ll D