昨天再看剑指offer的时候,在面试题9中提到了三种实现计算斐波那契数列的方法.在这里实现三种做法貌似还有一个O(1)的计算方法,也就是斐波那契数列是可以直接推到出来的.
1.常规的递归算法
def fib(n):
if n <= 0:
return 0
if n == 1:
return 1
return fib(n - 1) + fib(n - 2)
print (fib(5))
这种递归算法有大量的重复计算
以f(4)为例
f(4) = f(3) + f(2) ;
f(3) = f(2) + f(1)
f(2) = f(1) + f(0)
时间复杂度是以指数的形式增长,O(2^n)
如果面试时候这样写,90%的概率你已经gg了
2.循环形式
递归主要是做了大量的重复计算,如果把每一项计算出来后直接保存,使用的时候再去调用,这样就减少那些不必要的计算.
def f(n):
a, b = 0, 1
while n:
a, b = b, a + b
n -= 1
return a
print (f(4))
只要记录好前面的,后面的计算就直接用了.时间复杂度是O(N)
3.以矩阵的形式计算
就是通过增加维度降低时间复杂度
可以通过数学归纳法得出
[[f(n), f(n - 1)], [f(n - 1), f(n - 2)]] = [[1, 1], [1, 0]]^(n - 1)
所以得出这个结论之后,要做的就是计算计算矩阵[[1,1], [1,0]]^(n - 1)
这可以考虑
a^n = a^(n /2 ) * a^(n / 2) if n % 2== 0
a^n = a^ (n - 1) * a^ (n - 1) * a if n%2 != 0
得到这些信息,就可以计算了
def mul(l1, trix):
return [sum(list(map(lambda x:x[0] * x[1], zip(l1, trix[:][0])))),\
sum(list(map(lambda x:x[0] *x[1], zip(l1, trix[:][1]))))]
def matrixMulti(trix1, trix2):
return [mul(trix1[0], trix2), mul(trix1[1], trix2)]
def main(n):
basicMatrix = [[1, 1], [1, 0]]
# 单位1
ans = [[1, 0], [0, 1]]
if n == 0:
return 0
if n == 1:
return 1
while n:
# n是奇数,先做一个乘法
if n&1:
ans = matrixMulti(ans, basicMatrix)
basicMatrix = matrixMulti(basicMatrix, basicMatrix)
n >>= 1
return ans[0][1]
for i in range(10):
print (main(i))
就可以得到最终的结果
这种基于递归用O(log(n))的求得n次方的方法值得重视.