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

来源:互联网 发布:视频解码软件 编辑:程序博客网 时间:2024/06/08 05:54

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

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








0 0
原创粉丝点击