算法解析——矩阵快速幂
一.简介
矩阵快速幂是一种对于矩阵连乘非常有效的算法
以矩阵 A A A为例,对于 A n A^n An,如果按照正常的方法,时间复杂度为 O ( n ) O(n) O(n),可如果考虑矩阵快速幂,我们可以将时间复杂度优化到 O ( log n ) O(\log n) O(logn)
二.快速幂
先考虑常数的情况,设有常数 x x x,对于 x n x^n xn,不妨如下考虑:
假如 n = 100110 n=100110 n=100110,那么 x n = x 100110 = x 100000 ∗ x 000100 ∗ x 000010 x^n=x^{100110}=x^{100000}*x^{000100}*x^{000010} xn=x100110=x100000∗x000100∗x000010,对于这种情况,我们可以采用如下方法进行优化
if __name__ == '__main__':
n = 10
x = 2
sum = x
ans = 1
while n > 0:
a = n & 1
if a == 1:
ans *= sum
sum *= sum
n >>= 1
print(ans)
其原理就是用 a n s ans ans记录答案,再用一个变量 s u m sum sum记录当前是 x x x的几次方(如: x 100000 , x 000100 , x 000010 x^{100000},x^{000100},x^{000010} x100000,x000100,x000010),对于 n n n的每一位进行判断,判断其是否为 1 1 1,每次是 n n n的该位为 1 1 1就拿 a n s ans ans乘以该 s u m sum sum,最后 a n s ans ans的结果即为所求
等于说,本题的算法复杂度实际上是 n n n的二进制位数,即 O ( log n ) O(\log n) O(logn)
三.矩阵快速幂
如果常数可以进行快速幂,那么矩阵同样可以,唯一不同的就在于每次进行的 s u m ∗ s u m , a n s ∗ s u m sum*sum,ans*sum sum∗sum,ans∗sum是矩阵之间的乘法,而不是常数之间的乘法,虽然会增加一定的复杂度,但这些复杂度的增加是常数级别的,最终的时间复杂度仍然为 O ( log n ) O(\log n) O(logn)
四.矩阵快速幂的应用
矩阵快速幂可以用于斐波那契数列的求和中
斐波那契数列的公式如下: f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n−1)+f(n−2),对其进行一定的改写,我们可以得出 { f ( n ) = f ( n − 1 ) + f ( n − 2 ) f ( n − 1 ) = f ( n − 1 ) \begin {cases} f(n)=f(n-1)+f(n-2) \\ f(n-1)=f(n-1)\end{cases} {f(n)=f(n−1)+f(n−2)f(n−1)=f(n−1)
将其转换成矩阵乘法,我们有 [ f ( n ) f ( n − 1 ) ] = [ 1 1 1 0 ] [ f ( n − 1 ) f ( n − 2 ) ] = [ 1 1 1 0 ] n − 2 [ f ( 2 ) f ( 1 ) ] \left[\begin{matrix} f(n) \\ f(n-1)\end{matrix}\right] = \left[\begin{matrix} 1 \ 1 \\ 1 \ 0\end{matrix}\right] \left[\begin{matrix} f(n-1) \\ f(n-2)\end{matrix}\right]=\left[\begin{matrix} 1 \ 1 \\ 1 \ 0\end{matrix}\right]^{n-2} \left[\begin{matrix} f(2) \\ f(1)\end{matrix}\right] [f(n)f(n−1)]=[1 11 0][f(n−1)f(n−2)]=[1 11 0]n−2[f(2)f(1)]
即我们可以直接通过公式+矩阵快速幂得到斐波那契数列的解,时间复杂度为求解 [ 1 1 1 0 ] n − 2 \left[\begin{matrix} 1 \ 1 \\ 1 \ 0\end{matrix}\right]^{n-2} [1 11 0]n−2的时间复杂度,即 O ( log n ) O(\log n) O(logn)