斐波那契数快速算法

定义

f i b ( n ) = { 0 i f    n = 0 1 i f    n = 1 f i b ( n − 2 ) + f i b ( n − 1 ) o t h e r w i s e fib(n)=\left\{\begin{matrix} 0&if\;n=0 \\1&if \;n=1 \\fib(n-2)+fib(n-1)&otherwise \end{matrix}\right. fib(n)=01fib(n2)+fib(n1)ifn=0ifn=1otherwise

一般计算方法

直接用递归实现

def fib(n):
	if n == 0:
		return 0
	elif n == 1:
		return 1
	else:
		return fib(n-2) + fib(n-1)

时间复杂度为 O ( φ n ) O(\varphi^n) O(φn),空间复杂度为 O ( n ) O(n) O(n),其中 φ \varphi φ为黄金分割率。

使用迭代实现
(1)

def fib(n):
	a, b = 0, 1
	for i in range(n):
		a, b = b, a + b
	return a

(2)

def fib(n):
	a, b = 0, 1
	while n:
		a, b = b, a + b
		n -= 1
	return a

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)

高效算法

考虑上面的迭代计算过程,迭代计算的核心思想是状态变换。
初始状态
a = 0 a=0 a=0
b = 1 b=1 b=1

状态更新
a ← b a\leftarrow b ab
b ← a + b b\leftarrow a+b ba+b

状态更新 n n n次即可得到 f i b ( n ) fib(n) fib(n) f i b ( n + 1 ) fib(n+1) fib(n+1)
这种状态更新形式事实上是线性变换,因此可用矩阵乘法表示。

( b a ) ← [ 1 1 1 0 ] ( b a ) \begin{pmatrix} b\\a \end{pmatrix} \leftarrow \begin{bmatrix}1&1\\1&0\end{bmatrix}\begin{pmatrix} b\\a \end{pmatrix} (ba)[1110](ba)

其中
T = [ 1 1 1 0 ] T=\begin{bmatrix}1&1\\1&0\end{bmatrix} T=[1110]
为线性变换矩阵。


s n = ( f i b ( n + 1 ) f i b ( n ) ) s_n=\begin{pmatrix}fib(n+1)\\fib(n)\end{pmatrix} sn=(fib(n+1)fib(n))

s 0 = ( 1 0 ) s_0=\begin{pmatrix}1\\0\end{pmatrix} s0=(10)

s n = T n s 0 s_n=T^ns_0 sn=Tns0
可根据此事实设计高效算法

s n = T n s 0 = { ( T 2 ) n 2 s 0 i f    n   i s   e v e n T n − 1 ( T s 0 ) i f    n   i s   o d d s_n=T^ns_0=\left\{\begin{matrix} (T^2)^{\frac{n}{2}}s_0&if\;n\,is\,even \\T^{n-1}(Ts_0)&if\;n\,is\,odd \end{matrix}\right. sn=Tns0={(T2)2ns0Tn1(Ts0)ifnisevenifnisodd

def fib(n)
	s0, s1 = 0, 1				#fib(0),fib(1)
	a, b, c, d = 1, 1, 1, 0		#变换矩阵
	while n:
		if n % 2 == 0:
			#n为偶数时,T<----T^2
			a, b, c, d = a**2 + b*c, b*(a + d), c*(a + d), b*c + d**2 
			n \= 2
		else:
			s0, s1 = c*s1 + d*s2, a*s1 + b*s2
			n -= 1
	return s0			

该算法的时间复杂度为 O ( l o g n ) O(logn) O(logn),空间复杂度为 O ( 1 ) O(1) O(1)

这里共使用了7个状态变量:n, s0, s1, a, b, c, d。考虑到变换矩阵 T T T为实对称矩阵,有b=c,因此可以减少一个状态变量。

def fib(n)
	s0, s1 = 0, 1				#fib(0),fib(1)
	a, b, c = 1, 1, 0		#变换矩阵
	while n:
		if n % 2 == 0:
			#n为偶数时,T<----T^2
			a, b, c = a**2 + b**2, b*(a + c), b**2 + c**2 
			n \= 2
		else:
			s0, s1 = b*s1 + c*s2, a*s1 + b*s2
			n -= 1
	return s0			

再考虑到, c = a − b c=a-b c=ab,变换矩阵只用两个变量a,b表示即可。

def fib(n)
	s0, s1 = 0, 1				#fib(0),fib(1)
	a, b = 1, 1		#变换矩阵
	while n:
		if n % 2 == 0:
			#n为偶数时,T<----T^2
			a, b= a**2 + b**2, b*(a + (a - b))
			n \= 2
		else:
			s0, s1 = b*s1 + (a-b)*s2, a*s1 + b*s2
			n -= 1
	return s0			
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值