动态规划矩阵解斐波那契数列(Fibonacci sequence)

概述

斐波那契数列问题就是已知递推式F(n) = F(n-1)+F(n-2),给出n,求F(n)的问题。一般给了范围后直接打表即可,这种方法我也不说了,本文主要研究利用矩阵乘法加速求解斐波那契数列的算法。


思路分析

我们先来了解一下做这道题的前置知识——矩阵乘法:

\begin{pmatrix} a & b \end{pmatrix}\begin{vmatrix} c &d \\ e & f \end{vmatrix}= \begin{pmatrix} a*c+b*e & a*d+b*f \end{pmatrix}

只需要这个简单的就足够了...,下面开始分析如何将斐波那契数列应用矩阵乘法做一个变形。

\begin{pmatrix} F(n) & F(n-1) \end{pmatrix}= \begin{pmatrix} F(n-1)+F(n-2) & F(n-1) \end{pmatrix}

\begin{pmatrix} F(n) & F(n-1) \end{pmatrix}= \begin{pmatrix} F(n-1)*1+F(n-2)*1 & F(n-1)*1+F(n-2)*0 \end{pmatrix}

\begin{pmatrix} F(n) & F(n-1) \end{pmatrix}= \begin{pmatrix} F(n-1)& F(n-2) \end{pmatrix}\begin{vmatrix} 1 &1 \\ 1 & 0 \end{vmatrix}

我们已知F(1)=1,F(2)=1,F(3)=2,F(4)=3...。将其带入公式:

当n=3时:

\begin{pmatrix} F(3) & F(2) \end{pmatrix}= \begin{pmatrix} F(2)& F(1) \end{pmatrix}\begin{vmatrix} 1 &1 \\ 1 & 0 \end{vmatrix}= \begin{pmatrix} 1& 1 \end{pmatrix}\begin{vmatrix} 1 &1 \\ 1 & 0 \end{vmatrix}

当n=4时:

\begin{pmatrix} F(4) & F(3) \end{pmatrix}= \begin{pmatrix} F(3)& F(2) \end{pmatrix}\begin{vmatrix} 1 &1 \\ 1 & 0 \end{vmatrix}= \begin{pmatrix} 1& 1 \end{pmatrix}\begin{vmatrix} 1 &1 \\ 1 & 0 \end{vmatrix}^{2}

由此可推出一般式:

\begin{pmatrix} F(n) & F(n-1) \end{pmatrix}= \begin{pmatrix} 1& 1 \end{pmatrix}\begin{vmatrix} 1 &1 \\ 1 & 0 \end{vmatrix}^{n-2}

从此,题目就变成了快速求矩阵的N次方问题,矩阵求幂运算和数字求幂运算大体相同,不了解数字快速幂的同学可以访问这里:传送门


代码

package data_structure;

import org.junit.Test;

public class Fibonacii {
    /**
     * 求两矩阵相乘
     * 
     * @param p
     * @param q
     * @return 结果矩阵
     */
    public int[][] matrixMulti(int[][] p, int[][] q) {
        int[][] res = new int[p.length][q[0].length];
        for (int i = 0; i < p.length; i++) {
            for (int j = 0; j < q[0].length; j++) {
                for (int k = 0; k < q.length; k++) {
                    res[i][j] += (p[i][k] * q[k][j]);
                }
            }
        }
        return res;
    }

    /**
     * 求幂运算
     * 
     * @param m
     */
    public int[][] matrixPow(int[][] m, int n) {
        int[][] res = new int[m.length][m[0].length];

        for (int i = 0; i < res.length; i++) {
            res[i][i] = 1;
        }

        int[][] temp = m;
        while (n != 0) {
            if ((n & 1) != 0) {
                res = matrixMulti(temp, res);
            }
            temp = matrixMulti(temp, temp);
            n >>= 1;
        }

        return res;
    }
    //此方法与matrixPow作用相同
    public int[][] matrixPow1(int[][] m, int n) {
        if (n == 0) {
            return m;
        } else if ((n & 1) == 0) {
            return matrixMulti(m, matrixPow1(m, n - 1));
        } else {
            int[][] temp = matrixPow1(m, n >> 1);
            return matrixMulti(temp, temp);
        }
    }

    public int fibonacii(int n) {
        if (n == 0) {
            return 0;
        }
        if (n == 1 || n == 2) {
            return 1;
        }
        int[][] base = { { 1, 1 }, { 1, 0 } };
        int[][] res = matrixPow(base, n - 2);
        return res[0][0] + res[1][0];
    }

    @Test
    public void main() {
        for (int i = 0; i < 10; i++)
            System.out.println(fibonacii(i));
    }

}

总结

一个O(log(N))的算法就出来了,对于F(N)=F(N-1)+F(N-2)来说,所需矩阵是一个2*2的,在进行矩阵乘法代码相当于常数时间内完成,进行矩阵幂运算时,时间复杂度为O(log(N)),所以整体时间复杂度为O(log(N))

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值