一、问题描述
给定一个方阵 ,求方阵
的
次幂
。
二、简单算法
直接想法是利用for循环不断进行方阵乘法,直到求出 ,算法时间复杂度是
,如此高的时间复杂度在实践中是走不通的。
三、快速算法
下面是用python实现的 方阵的快速实现。
右移一位最多执行
次就会变成 0,故算法的时间复杂度是
,
表示方阵的行数或列数,基本思想是复用已经计算出来的部分结果,减少重复计算。
# !/usr/bin/python
# coding=utf-8
# 两个方阵的乘法
def multiply(a, b):
c = [[1,0],[0,1]]
for i in range(0,2):
for j in range(0,2):
c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j]
return c
# 迭代法
def quick_matrix_pow(a,n):
ans = [[1,0],[0,1]]
while n > 0:
# 如果n的二进制表示最低位是1
if n & 1 == 1:
ans = multiply(ans, a)
n >>= 1
if n > 0:
a = multiply(a, a)
return ans
'''
# 递归法,n太大可能造栈溢出
def quick_matrix_pow(a,n):
if n == 1:
return a
c = f(a,n/2)
d = multiply(c,c)
if n % 2 == 0:
return d
else:
return multiply(d,a)
'''
def main():
a = [[1,3],[2,2]]
n = 9
ans = quick_matrix_pow(a, n)
for i in range(0,2):
print("[%d\t%d]" % (ans[i][0],ans[i][1]))
if __name__ == '__main__':
main()
# 输出
[104857 157287]
[104858 157286]
四、快速算法的正确性
快速算法的代码实现非常简洁,但是如何理解它的正确性那?通过下面的推理可以直观的来解释算法的正确性, 分别等于8、9、11。
由算法描述,每次循环先检查 的二进制表示的最低位是否为1,是1的话就对ans赋值为
,
表示该最低位在
的二进制表示中所处的位置;否则, 将
的二进制表示右移一位(高位会进行补0),令
。
一般的,如果 的二进制表示有
位,则有
其中, 是
的二进制表示中第
位的值(0或者1),简单来说,就说忽略为 0 的位,值为1的位计算
,再进行累乘。
五、在斐波那契数列上的应用
斐波那契递推公式为:,如果
不是很大的话,直接根据公式迭代便可求出
,代码如下。递归解法(结合查表)和迭代解法复杂度相同,但是多了很多栈空间的操作,而且容易造成栈溢出,故不推荐采用递归解。
# !/usr/bin/python
# coding=utf-8
def fibonacci(n):
if n < 0:
raise Exception("Must be positive integer")
if n <= 1:
return n
a = 0
b = 1
c = a + b
# 采用了滚动数组
while n > 2:
a = b
b = c
c = a + b
n = n - 1
return c
def main():
n = 2
print(fibonacci(n))
if __name__ == '__main__':
main()
在我的机器上,当 n = 1000000时,运算时间已经达到5秒左右,如果 n = 100000000,速度是超级慢的,该算法的复杂度是 。
但是,仔细观察可以发现
递推的展开上式有
现在关键问题就是求
这是快速方阵幂算法所解决的问题, 因此有了这个中间过程的解, 自然可以求出,下面是使用了快速方阵幂的斐波那契算法。
# !/usr/bin/python
# coding=utf-8
from quick_matrix_pow import *
import time
def QuickFibonacci(n):
if n < 0:
raise Exception("Must be positive integer")
if n <= 1:
return n
m = [[1,1],[1,0]]
a = quick_matrix_pow(m, n-1)
return a[0][0]
def main():
n = 10000000
QuickFibonacci(n)
if __name__ == '__main__':
main()
当 n = 10000000,时间大约用了21秒,而普通的迭代算法已经超过了1分钟,算法的时间复杂度同快速矩阵幂算法。
六、思想推广
快速方阵幂的思想可以用来解决很多具有迭代性质的问题,斐波那契是其中的特例,遇到具有迭代性质的问题时,不妨考虑下可否借鉴快速方阵幂的实现来加快迭代算法的求解。