本文正在参加 人工智能创作者扶持计划
上一篇🔗快速幂(一)|小巧而强大的算法
本文阅读时间约5分钟,你将获得:
通俗易懂的矩阵快速幂讲解,不懂不要小钱钱的那种~
本文是快速幂算法的应用的第一篇,其他快速幂应用还包括:
简介
矩阵快速幂算法是将快速幂算法应用于矩阵乘法的一种算法,
其主要思想是通过将矩阵乘法转化为矩阵加法和矩阵乘法的组合,从而将时间复杂度降低到O ( log n ) O(\log n) O ( log n ) 。
下面以斐波那契数列为例进行讲解。
斐波那契数列
斐波那契数列的通项公式为:
F n = { 1 n = 0 1 n = 1 F n − 1 + F n − 2 n > 1 F_n= \begin{cases}1 & n=0 \\ 1 & n=1 \\ F_{n-1}+F_{n-2} & n>1\end{cases} F n = ⎩ ⎨ ⎧ 1 1 F n − 1 + F n − 2 n = 0 n = 1 n > 1
使用矩阵表示斐波那契数列,则有:
( F n − 1 F n ) = ( 0 1 1 1 ) ( F n − 2 F n − 1 ) \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) ( F n − 1 F n ) = ( 0 1 1 1 ) ( F n − 2 F n − 1 )
为什么可以用矩阵快速幂
写出斐波那契数列:
1 1 2 3 5 8 13 21 ......
由通项公式可知,当n ≥ 3 n\geq 3 n ≥ 3 时,F n F_n F n 的值为前两项之和,
那么我们将第一项和第二项为第一组,第二项和第三项为第二组,能否通过第一组的某种运算得到第二组的结果呢?
设转移矩阵( a b c d ) \left(\begin{array}{ll}a & b \\ c & d\end{array}\right) ( a c b d ) 使得
( F n − 1 F n ) = ( a b c d ) ( F n − 2 F n − 1 ) \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) ( F n − 1 F n ) = ( a c b d ) ( F n − 2 F n − 1 )
将第一组和第二组分别代入上式,得到:
( 1 2 ) = ( a b c d ) ( 1 1 ) \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) ( 1 2 ) = ( a c b d ) ( 1 1 )
和
( 2 3 ) = ( a b c d ) ( 1 2 ) \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) ( 2 3 ) = ( a c b d ) ( 1 2 )
由矩阵乘法定义可得线性方程组如下:
a × 1 + b × 1 = 1 a \times 1 + b \times 1 = 1 a × 1 + b × 1 = 1
c × 1 + d × 1 = 2 c \times 1 + d \times 1 = 2 c × 1 + d × 1 = 2
a × 1 + b × 2 = 2 a \times 1 + b \times 2 = 2 a × 1 + b × 2 = 2
c × 1 + d × 2 = 3 c \times 1 + d \times 2 = 3 c × 1 + d × 2 = 3
解得
a = 0
b = 1
c = 1
d = 1
故,转移矩阵应为( 0 1 1 1 ) \left(\begin{array}{ll}0 & 1 \\ 1 & 1\end{array}\right) ( 0 1 1 1 )
又因为
( 2 3 ) = ( a b c d ) ( 1 2 ) = ( a b c d ) ( a b c d ) ( 1 1 ) = ( a b c d ) 2 ( 1 1 ) \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) ( 2 3 ) = ( a c b d ) ( 1 2 ) = ( a c b d ) ( a c b d ) ( 1 1 ) = ( a c b d ) 2 ( 1 1 )
以此类推,fibonacci也可以根据该式转化为转移矩阵求幂的问题:
( F n − 1 F n ) = ( a b c d ) n − 1 ( F 0 F 1 ) \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) ( F n − 1 F n ) = ( a c b d ) n − 1 ( F 0 F 1 )
代码实现
具体地,我们可以定义一个矩阵乘法的快速幂函数,例如:(递归的)
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.
"""
if n == 1 :
return A
if n % 2 == 0 :
tmp = matrix_power(A, n//2 )
return tmp @ tmp
else :
return A @ matrix_power(A, n + 1 )
参考资料
一文彻底搞懂快速幂(原理实现、矩阵快速幂) - bigsai - 博客园 (cnblogs.com)
【竞赛向】斐波那契数列的矩阵快速幂求法_哔哩哔哩_bilibili