【相当困难】斐波那契系列问题的递归和动态规划-Java:补充题目2

本文介绍了一个关于牛群数量随时间增长的数学问题及其高效解法。通过对递归和动态规划的理解,提出了一种时间复杂度为O(logN)的算法,并通过矩阵运算实现了加速。

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程大家好!欢迎来到我的网站! 人工智能被认为是一种拯救世界、终结世界的技术。毋庸置疑,人工智能时代就要来临了,科… 继续阅读 前言https://www.captainai.net/troubleshooter

package live.every.day.ProgrammingDesign.CodingInterviewGuide.RecursionAndDynamicPrograming;

/**
 * 斐波那契系列问题的递归和动态规划
 *
 * 【题目】
 * 给定整数N,返回斐波那契数列的第N项。
 *
 * 【补充题目1】
 * 给定整数N,代表台阶数,一次可以跨2个或者1个台阶,返回有多少种走法。
 *
 * 【补充题目2】
 * 假设农场中成熟的母牛每年只会生1头小母牛,并且永远不会死。第一年农场有1只成熟的母牛,从第二年开始,母牛开始生小母牛。
 * 每只小母牛3年之后成熟又可以生小母牛。给定整数N,求出N年后牛的数量。
 *
 * 【要求】
 * 对以上所有的问题,请实现时间复杂度O(logN)的解法。
 *
 * 【难度】
 * 相当困难
 *
 * 【解答】
 * 补充问题2。
 *
 * 所有的牛都不会死,所以第N-1年的牛会毫无损失地活到第N年。同时所有成熟的优缺点都会生出1头新的牛,那么成熟牛的数量如何
 * 估计?就是第N-3年的所有牛,到第N年肯定都是成熟的牛,其间出生的牛肯定都没有成熟。所以C(n)=C(n-1)+C(n-3),初始项为
 * C(1)==1,C(2)==2,C(3)==3。这个和斐波那契数列又十分类似,只不过C(n)依赖C(n-1)和C(n-3)的值,而斐波那契数列F(n)
 * 依赖F(n-1)和F(n-2)的值。同样可以很轻易地写出O(2^N)与O(N)的方法,请参看如下代码中的c1和c2方法。
 *
 * O(logN)的方法。C(n)=C(n-1)+C(n-3)是一个三阶递推数列,一定可以用矩阵乘法的形式表示,且状态矩阵为3x3的矩阵。
 * (Cn,Cn-1,Cn-2)=(Cn-1,Cn-2,Cn-3)x|abc,def,ghi|
 * 把前5项C(1)==1,C(2)==2,C(3)==3,C(4)==4,C(5)==6代入,求出状态矩阵:
 * |abc,def,ghi|=|110,001,100|
 * 求矩阵之后,当n>3时,原来的公式可化简为:
 * (Cn,Cn-1,Cn-2)=(C3,C2,C1)x|110,001,100|^n-3=(3,2,1)x|110,001,100|^n-3
 * 接下来的过程又是利用加速矩阵乘法的方式进行实现,具体请参看如下代码中的c3方法。
 *
 * 如果递归式严格符合F(n)=axF(n-1)+bxF(n-2)+...+kxF(n-i),那么它就是一个i阶的递推式,必然有与ixi的状态矩阵有关的
 * 矩阵乘法的表达。一律可以用加速矩阵乘法的动态规划将时间复杂度降为O(logN)。
 *
 * @author Created by LiveEveryDay
 */
public class FibonacciSeries3 {

    public static int c1(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }
        return c1(n - 1) + c1(n - 3);
    }

    public static int c2(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }
        int res = 3;
        int pre = 2;
        int prepre = 1;
        int tmp1 = 0;
        int tmp2 = 0;
        for (int i = 4; i <= n; i++) {
            tmp1 = res;
            tmp2 = pre;
            res = res + prepre;
            pre = tmp1;
            prepre = tmp2;
        }
        return res;
    }

    public static int c3(int n) {
        if (n < 1) {
            return 0;
        }
        if (n == 1 || n == 2 || n == 3) {
            return n;
        }
        int[][] base = {{1, 1, 0}, {0, 0, 1}, {1, 0, 0}};
        int[][] res = matrixPower(base, n - 3);
        return 3 * res[0][0] + 2 * res[1][0] + res[2][0];
    }

    private static int[][] matrixPower(int[][] m, int p) {
        int[][] res = new int[m.length][m[0].length];

        // 先把res设为单位矩阵,相当于整数中的1
        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;
    }

    public static void main(String[] args) {
        int n = 8;
        System.out.printf("c1: %d%n", c1(n));
        System.out.printf("c2: %d%n", c2(n));
        System.out.printf("c3: %d%n", c3(n));
    }

}

// ------ Output ------
/*
c1: 19
c2: 19
c3: 19
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值