斐波那契数列相关问题总结

一. 原问题

在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*),即从第三项开始,每一项等于前两项之和。

输入格式:输入包括一行,包括一个整数N (0≤N≤50)。

输出格式:输出包括一行,包括一个整数,为斐波那契数列的第 N 项的值。

  1. 递归方法
    时间复杂度为O(2^n)。

    import java.util.Scanner;
    
    public class Fibonacci_1 {
    
        public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            int n = input.nextInt();
            long f = fib(n);
            System.out.println(f);
        }
    
        public static long fib(int n) {
            if(n == 0){
                return 0;
            }else if (n == 1){
                return 1;
            }else {
                return fib(n - 1) + fib(n - 2);
            }
        }
    }
  2. 数组存储,动态规划

    当一个问题可以分解成若干重复的子问题时,运用动态规划的思想:只需要将子问题求解一次,以后再遇到,直接调用,所以新建一个数组用于存储子问题的结果。(以空间换时间)

    import java.util.Scanner;
    
    public class Fibonacci_2 {
    
        static Scanner input = new Scanner(System.in);
        static int n = input.nextInt();
        static long[] result = new long[n + 1];
    
        public static void main(String[] args) {
            long f = fib(n);
            System.out.println(f);
        }
    
        public static long fib(int n) {
            long f = 0;
            if(n == 0){
                f = 0;
            }else if (n == 1){
                f = 1;
            }else if (result[n] > 0){
                return result[n];
            }else {
                f = fib(n - 1) + fib(n - 2);
            }
            result[n] = f;
            return f;
        }
    }
    
  3. 递推方法
    时间复杂度为O(n)

    import java.util.Scanner;
    
    public class Fibonacci_3 {
        public static void main(String[] args) {
            long f0 = 0;
            long f1 = 1;
            long f = 0;
            Scanner input = new Scanner(System.in);
            int n = input.nextInt();
    
            if(n == 0){
                f = 0;
            }else if(n == 1){
                f = 1;
            }else {
                for(int i = 2; i <= n; i++){
                    f = f0 + f1;
                    f0 = f1;
                    f1 = f;
                }
            }
    
            System.out.println(f);
        }
    }
  4. 矩阵相乘算法

    推导过程:
    Fibonacci_1
    Fibonacci_2
    由此演变成了求Fibonacci_3此矩阵的(n - 1)次方的过程。

    import java.util.Scanner;
    
    public class Fibonacci_4{
    
        public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            int n = input.nextInt();
            long f = fib(n);
            System.out.println(f);
        }
    
        public static long[][] baseMartrixMulti(int n) {
            long[][] result = {{1, 0}, {0, 1}};//单位阵
            long[][] base = {{1, 1}, {1, 0}};
            long[][] temp = {{1, 0}, {0, 1}};
            for (int i = 0; i < n; i++){
                result[0][0] = temp[0][0] * base[0][0] + temp[0][1] * base[1][0];
                result[0][1] = temp[0][0] * base[0][1] + temp[0][1] * base[1][1];
                result[1][0] = temp[1][0] * base[0][0] + temp[1][1] * base[1][0];
                result[1][1] = temp[1][0] * base[0][1] + temp[1][1] * base[1][1];
                temp[0][0] = result[0][0];//特别注意,数组赋值赋的是引用,不能直接temp = result;
                temp[0][1] = result[0][1];
                temp[1][0] = result[1][0];
                temp[1][1] = result[1][1];
            }
            return result;
        }
    
        public static long fib(int n) {
            long f = 0;
            if(n != 0){
                long[][] trans = baseMartrixMulti(n - 1);
                f = trans[0][0];//意义为下两条注释的语句
                //long[][] bas = {{1}, {0}};
                //f = trans[0][0] * bas[0][0] + trans[0][1] * bas[1][0];
            }
            return f;
        }
    }

    矩阵相乘和乘方可以单独抽象出来函数,此处只是为了解决固定矩阵的乘方问题,没有给出普适代码,若有需要参考 矩阵乘法求斐波那契数列

    此过程中发现乘方优化算法,参考 乘方的优化算法,可结合到矩阵乘方,待研究后贴出代码。

  5. 公式法

    Fibonacci_4

    万能的数学家得出斐波那契数列通项公式如上,推导过程略(其实是因为看不懂,有兴趣自行百度 orz)。又称为“比内公式”,是用无理数表示有理数的一个范例。

    代码实现如下:

    import java.util.Scanner;
    
    public class Fibonacci_5 {
    
        public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            int n = input.nextInt();
            long f = (long)((Math.pow((1 + Math.sqrt(5)) / 2, n) - Math.pow((1 - Math.sqrt(5)) / 2, n)) / Math.sqrt(5));
            System.out.println(f);
        }
    }

二. 引申问题

  1. 爬楼梯问题

    假设你现在正在爬楼梯,楼梯有 n 级。每次你只能爬 1 级或者 2 级,那么你有多少种方法爬到楼梯的顶部?

    输入格式:第一行输入一个整数 n(1≤n≤50),代表楼梯的级数。

    输出格式:输出爬到楼梯顶部的方法总数。

    其实相当于斐波那契问题,只是初始条件改变。f(1) = 1, f(2) = 2, n > 2时,f(n) = f(n - 1) + f(n - 2) 。 (若用矩阵运算可以将base矩阵减少一阶,也可以虚拟假设 f(0) = 1)

    任选一种以上方法给出代码:

    import java.util.Scanner;
    
    public class Climb {
        public static void main(String[] args) {
            long f0 = 1;
            long f1 = 1;
            long f = 0;
            Scanner input = new Scanner(System.in);
            int n = input.nextInt();
            if(n == 1){
                f = 1;
            }else{
                for(int i = 2; i <= n; i++){
                    f = f0 + f1;
                    f0 = f1;
                    f1 = f;
                }
            }
            System.out.println(f);
        }
    }
  2. 疯狂跳台阶
    (题目来源于http://blog.csdn.net/xingyanxiao/article/details/47055973

    一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
    因此,Fibonacci_5 。f(1)=1,f(2)=2。

    代码略。

  3. 兔子问题

    已知第一个月有一对刚出生的兔子,从出生第三个月起,一对兔子每个月可以生一对小兔子。假如没有发生死亡,则第一个月开始,第N个月后会有多少对?

    这里以对为单位,从第一个月开始,每个月总共的兔子数量就是1, 1, 2, 3, 5, 8, 13……可以看出前两个月为1,从第三个月开始,当月的数量为前两个月数量之和,所以 f(n) = f(n - 1) + f(n - 2)(n > 2)。同时f(1) = 1, f(2) = 1。

    代码实现同标准数学问题。

类似斐波那契问题还有很多,注意递推公式的推导即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值