码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-06-25 09:01:36      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:fibonacci   斐波那契数列   java   编程之美-2-9   

编程之美 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的
次幂,因此,实现代码与上面是类似的。
这个里面涉及到二阶矩阵乘法的运算,直接利用矩阵乘法的定义还是比较好实现的。如果涉及到高阶矩阵的乘法,则就应采用分块矩阵的乘法来进行解决了,在算法导论这本书上有详细的讲解,这里不再介绍

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

标签:fibonacci   斐波那契数列   java   编程之美-2-9   

原文地址:http://blog.csdn.net/u010412719/article/details/46628087

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!