Water2Wine

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

题目:给定整数N,返回斐波那契数列的第N项

变式1:给定整数N,代表台阶数,一次可以跨2个或者1个台阶,返回有多少种走法
跨到最后一节台阶的走法等同于跨到倒数第一个台阶和倒数第二个台阶走法之和,就回到了求斐波那契数列的基本题

变式2:假设农场种成熟的母牛每年只会生1头小母牛,并且永远不会死。第一年农场有1只成熟的母牛,从第二年开始,母牛开始生小母牛。每只小母牛3年之后成熟又可以生小母牛。给定整数N,求出N年后牛的数量
我们可以想办法找第x年的牛的数量和第x-1年牛的数量的关系,第x年牛的数量等于第x-1年牛的数量加上第x年生的小牛的数量,而生的小牛的数量由成熟母牛数决定,成熟母牛数等于第x-3年所有牛的数量,即可得到斐波那契数列的变式递推式

解法1:
递归解法,时间复杂度O(2^N)

private static int getFibonacciByrec(int N) {
        if (N <= 0) {
            return -1;
        }
        if (N == 1 || N == 2) {
            return 1;
        }
        return getFibonacciByrec(N - 1) + getFibonacciByrec(N - 2);
    }

解法2:
迭代解法,时间复杂度O(N)

基本原理是记忆化递归,通过记录已经递归过的值从而大幅降低时间复杂度

private static int getFibonacciByIter(int N) {
        if (N <= 0) {
            return -1;
        }
        if (N == 1 || N == 2) {
            return 1;
        }
        int first = 1;
        int second = 1;
        int ans = 2;
        for (int i = 3;i <= N;i++) {
            ans = first + second;
            first = second;
            second = ans;
        }
        return ans;
    }

解法3:
矩阵快速幂解法,时间复杂度O(logN)
因为递归式严格遵循F(N)=F(N-1)+F(N-2),是一个二阶地推数列,一定可以用矩阵乘法的形式表示,且状态矩阵为2x2的矩阵
最后会转变成如何用最快的方法求一个矩阵的N次方的问题,通过将N按位累乘即可实现logN时间复杂度求解

private static int getFibonacciByQuickExpo(int N) {
        if (N <= 0) {
            return -1;
        }
        if (N == 1 || N == 2) {
            return 1;
        }
        int[][] base = {{1,1},{1,0}};
        int[][] res = matrixPower(base, N - 2);
        return res[0][0] + res[1][0];
    }
    private static int[][] matrixPower(int[][] m, int p) {
        int[][] res = new int[m.length][m[0].length];
        // 先把res设为单位矩阵
        for (int i = 0;i < res.length;i++) {
            res[i][i] = 1;
        }
        int[][] tmp = m;
        for (;p != 0;p >>= 1) {
            if ((p & 1) != 0) {
                res = multiMatrix(res, tmp);
            }
            tmp = multiMatrix(tmp, tmp);
        }
        return res;
    }
    private static int[][] multiMatrix(int[][] m1, int[][] m2) {
        int[][] res= new int[m1.length][m2[0].length];
        for (int i = 0;i < m2[0].length;i++) {
            for (int j = 0;j < m1.length;j++) {
                for (int k = 0;k < m2.length;k++) {
                    res[i][j] += m1[i][k] * m2[k][j];
                }
            }
        }
        return res;
    }
posted on 2020-06-29 16:46  Water2Wine  阅读(412)  评论(0编辑  收藏  举报