快速幂(二)|矩阵快速幂求解fibonacci

381 阅读2分钟

本文正在参加 人工智能创作者扶持计划

上一篇🔗快速幂(一)|小巧而强大的算法

本文阅读时间约5分钟,你将获得:

通俗易懂的矩阵快速幂讲解,不懂不要小钱钱的那种~

本文是快速幂算法的应用的第一篇,其他快速幂应用还包括:

  • 快速幂取模
  • 高精快速幂

简介

矩阵快速幂算法是将快速幂算法应用于矩阵乘法的一种算法,

其主要思想是通过将矩阵乘法转化为矩阵加法和矩阵乘法的组合,从而将时间复杂度降低到O(logn)O(\log n)

下面以斐波那契数列为例进行讲解。

斐波那契数列

斐波那契数列的通项公式为: Fn={1n=01n=1Fn1+Fn2n>1F_n= \begin{cases}1 & n=0 \\ 1 & n=1 \\ F_{n-1}+F_{n-2} & n>1\end{cases}

使用矩阵表示斐波那契数列,则有:

(Fn1Fn)=(0111)(Fn2Fn1)\left(\begin{array}{c}F_{n-1} \\ F_n\end{array}\right)=\left(\begin{array}{ll}0 & 1 \\ 1 & 1\end{array}\right)\left(\begin{array}{l}F_{n-2} \\ F_{n-1}\end{array}\right)

为什么可以用矩阵快速幂

写出斐波那契数列:

1 1 2 3 5 8 13 21 ......

由通项公式可知,当n3n\geq 3时,FnF_n的值为前两项之和,

那么我们将第一项和第二项为第一组,第二项和第三项为第二组,能否通过第一组的某种运算得到第二组的结果呢?

设转移矩阵(abcd)\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)使得 (Fn1Fn)=(abcd)(Fn2Fn1)\left(\begin{array}{c}F_{n-1} \\ F_n\end{array}\right)=\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)\left(\begin{array}{l}F_{n-2} \\ F_{n-1}\end{array}\right)

将第一组和第二组分别代入上式,得到:

(12)=(abcd)(11)\left(\begin{array}{c}1\\ 2\end{array}\right)=\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)\left(\begin{array}{l}1 \\ 1\end{array}\right)

(23)=(abcd)(12)\left(\begin{array}{c}2\\ 3\end{array}\right)=\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)\left(\begin{array}{l}1 \\ 2\end{array}\right)

由矩阵乘法定义可得线性方程组如下:

a×1+b×1=1a \times 1 + b \times 1 = 1

c×1+d×1=2c \times 1 + d \times 1 = 2

a×1+b×2=2a \times 1 + b \times 2 = 2

c×1+d×2=3c \times 1 + d \times 2 = 3

解得 a = 0 b = 1 c = 1 d = 1

故,转移矩阵应为(0111)\left(\begin{array}{ll}0 & 1 \\ 1 & 1\end{array}\right)

又因为

(23)=(abcd)(12)=(abcd)(abcd)(11)=(abcd)2(11)\left(\begin{array}{c}2\\3\end{array}\right)=\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)\left(\begin{array}{l}1 \\ 2\end{array}\right) \\ \quad \quad \quad =\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)\left(\begin{array}{l}1 \\ 1\end{array}\right)\\ \quad \quad \quad =\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)^2\left(\begin{array}{l}1 \\ 1\end{array}\right)

以此类推,fibonacci也可以根据该式转化为转移矩阵求幂的问题:

(Fn1Fn)=(abcd)n1(F0F1)\left(\begin{array}{c}F_{n-1} \\ F_n\end{array}\right)=\left(\begin{array}{ll}a & b \\ c & d\end{array}\right)^{n-1}\left(\begin{array}{l}F_{0} \\ F_{1}\end{array}\right)

代码实现

具体地,我们可以定义一个矩阵乘法的快速幂函数,例如:(递归的)

def matrix_power(A, n):
    """
    This function raises a matrix A to the power of n using binary exponentiation.
    :param A: The matrix to be raised to a power.
    :param n: The power to raise the matrix to.
    :return: The resulting matrix.
    """
    # 如果n等于1,返回A
    if n == 1:
        return A
    # 如果n是偶数,递归调用matrix_power(A, n//2)并返回结果的平方
    if n % 2 == 0:
        tmp = matrix_power(A, n//2)
        return tmp @ tmp
    # 如果n是奇数,返回A乘以matrix_power(A, n + 1)的结果
    else :
        return A @ matrix_power(A, n + 1)

参考资料

一文彻底搞懂快速幂(原理实现、矩阵快速幂) - bigsai - 博客园 (cnblogs.com)

【竞赛向】斐波那契数列的矩阵快速幂求法_哔哩哔哩_bilibili