【算法导论学习-28】Fibonacci数列及其相关

1、解决方案

   Fibonacci数列增长很快,第100个已经到了1020次方,64位计算机才表示到19次方。所以这里统一采用计算第40个数来比较性能。实际上,4个字节的int类型只能计算到第48Fibonacci数(以0112开头)为1836 311 903,一个18亿左右的数字

1)递归方法——写法简单,效率非常低下

public class Fibonacci {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        long start=System.nanoTime();   //获取开始时间
         int fibonacciNO=getFibonacci(40);
         long end=System.nanoTime(); //获取结束时间
         System.out.println("程序运行时间: "+(end-start)+"ns");
         System.out.println(fibonacciNO);
    }
    /* 递归方案 */
    public static int getFibonacci(int n) {
        if (n == 1) {
            return 0;
        } else if (n == 2) {
            return 1;
        } else {
            return getFibonacci(n - 1) + getFibonacci(n - 2);
        }
    }
}
******************************************************************

输出:程序运行时间: 687841156ns
63245986

2)动态规划方法——写法简单,非常高效,复杂度O(n)

思路:算法导论370页课后题15.1-5,符合动态规划的一个特性——当前问题调用了两个子问题。

public class Fibonacci {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
      
        long start=System.nanoTime();   //获取开始时间
         int[] fibonacciNO=getFibonacci(40);
         long end=System.nanoTime(); //获取结束时间
         System.out.println("程序运行时间: "+(end-start)+"ns");
         for (int i : fibonacciNO) {
         System.out.println(i);
         }
    }
    /*自底向上进行计算*/
    public static int[] getFibonacci(int n) {
        int[] temp=new int[n];
        temp[0]=0;
        temp[1]=1;
        for (int i = 2; i < n; i++) {
            temp[i]=temp[i-1]+temp[i-2];
        }
        return temp;
    }
}
*****************************************

程序运行时间: 5131ns
63245986

3)通项公式方法——投机取巧,比较低效

思路:算法导论59页

public class Fibonacci {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        long start=System.nanoTime();   //获取开始时间
        System.out.println(getFibonacci(40));
         long end=System.nanoTime(); //获取结束时间
         System.out.println("程序运行时间: "+(end-start)+"ns");
 
    }
    public static int getFibonacci(int i) {
        float root=(float) ((1+Math.sqrt(5))/2);
        return (int) Math.round(Math.pow(root, i)/Math.sqrt(5));
    }
 
}
*****************************************

控制台输出:

102334197

程序运行时间: 655532ns

4)矩阵法——写法复杂,最高效,复杂度O(lgn)

  参考: http://zhedahht.blog.163.com/blog/static/25411174200722991933440/

2、相关的数学问题

1)排列组合
    有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?
    这就是一个斐波那契数列:登上第一级台阶有一种登法;登上两级台阶,有两种登法;登上三级台阶,有三种登法;登上四级台阶,有五种登法……
1,2,3,5,8,13……所以,登上十级,有89种走法。
2)数列中相邻两项的前项比后项的极限
   当n趋于无穷大时,F(n)/F(n+1)的极限是多少?
   这个可由它的通项公式直接得到,极限是(-1+√5)/2,这个就是黄金分割的数值,也是代表大自然的和谐的一个数字。

3、【一道面试题】如何判断一个数是不是Fibonacci数?(我的一点思路,还没有找到最终答案)

   讨论区:http://bbs.csdn.net/topics/120067216

1)在数比较小的时候(小于20724

   A verynice test is that N is a Fibonacci number if and only if 5 n^2 + 4 or 5n^2 – 4 is a squarenumber.

   即判断5 n^2 + 4 or 5n^2 – 4 是否是完全平方数,这里引出一个算法问题:“如何判断一个数是完全平方数?”,参考http://blog.sina.com.cn/s/blog_5a4882970102dxa5.html。这里主要讲完全平方数必然是连续奇数和:1+3+5+7+....+(2*n-1)=n^2。

public class Fibonacci {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        long start=System.nanoTime();   //获取开始时间
         int[] fibonacciNO=getFibonacci(48);
         long end=System.nanoTime(); //获取结束时间
         System.out.println("程序运行时间: "+(end-start)+"ns");
         for (int i : fibonacciNO) {
             System.out.print(isFibonacciNo(i));
        }
    }
   /*是否是Fibonacci数*/
    public static boolean isFibonacciNo(int n) {
     /*5 n^2 + 4如果大于Integer.MAX_VALUE则表明无法做判断了*/
     if (n>Math.pow((Integer.MAX_VALUE-4)/5, 0.5)) {
             System.out.print("无法判断——");
             return false;
        }

        int temp=(int) (5*Math.pow(n, 2));
        return isPerfectSquareNo(temp+4)||isPerfectSquareNo(temp-4);
    }
   /*完全平方数的判断*/
    public static boolean isPerfectSquareNo(int n) {
        for (int i = 1; n >0; i+=2) {
            n-=i;
        }
        return n==0;
    }
     /*自底向上进行计算*/
     public static int[] getFibonacci(int n) {
     int[] temp=new int[n];
     temp[0]=0;
     temp[1]=1;
     for (int i = 2; i < n; i++) {
     temp[i]=temp[i-1]+temp[i-2];
     }
     return temp;
     }
}
***********************************************

  程序测试表明,4个字节的int类型能只能判断到(int)Math.pow((Integer.MAX_VALUE-4)/5, 0.5)),大约20724,即最多可以判断2万个数而已。

2)、在数字比较大的情况下(整个Int长度内判断)

思路1

   使用动态规划方法生成Fibonacci数列,直到生成的Fibonacci数列等于n返回true,大于n返回false

思路2

。。。。待续,绝对应该有比较高效的算法。。。。。








你可能感兴趣的:(《算法导论》学习)