斐波那契数列的复杂度分析与优化

斐波那契数列的时间复杂度

# 斐波那契递归函数

def fib(n):
	if n < 3:
		return 1
	return fib(n-2) +fib(n-1)

分析:

​ 使用递归树的方式来计算斐波那契数列的时间复杂度

​ 这里假设我们在递归的最后两层进行了n次操作

在这里插入图片描述

​ 由斐波那契的递归树图我们可以看出,从下到上进行递归运算的时候,程序运行的次数是以2^x方式增加的。

​ 我们来计算一下f(7)的运行次数

​ 想要得到运行次数,首先我们要得到递归的深度,其中有2层为基本层

​ n = 7 - 2 = 5

​ 计算运行次数

​ T(n) = 2^0 + 2^1 + 2^2 + 2^3 + n = 2^4 + n -1

​ 如果递归的深度足够深的话,最后两个基数层的(n-1)次相比于2的指数级可以忽略不计,所以斐波那契的时间复杂度为

​ O(fib(n)) = O(2^n)

斐波那契数列的空间复杂度

空间复杂度主要是看内存的占用空间,在计算斐波那契数列时,会在内存中开辟多个内存空间用来进行运算,我们来分析一下它的空间占用情况。

def main():
	fib(7)
if __name__ == "main":
	main()

分析步骤:

  1. 执行main函数,main进栈并占据一块空间
  2. 执行fib(7),fib(7)=fib(6) + fib(5),无法直接得到fib(7)的值,故fib(7)会进栈并占用一块空间
  3. 接下来计算fib(6)=fib(5)+fib(4)和fib(5)=fib(4)+fib(3),均无法直接得到值,所以fib(6)和fib(5)进栈并分别占用一块空间
  4. 以此类推,直至递归的最底层fib(1)和fib(2)进栈
  5. 当fib(1)和fib(2)进栈,fib(1)=fib(2)=1,它们两个是由确切的值的,所以在它们进栈后,得到1后会立即被弹出,并且切换到它的上一个节点中,即f(3)中,此时计算出f(3)=f(1)+f(2)=2
  6. f(3)得到结果后,会被从栈中弹出,并且切换到f(3)的上一个节点中,即f(4)中,因为f(4)=f(3)+f(2),所以f(3)和f(2)会再次进栈,f(3)进栈后重复第5步过程后弹出,f(2)进栈后被赋值为1后弹出,此时f(4)=f(3)+f(2)=2+1=3,f(4)得到值后被弹出,切换到f(4)的上一个节点,即f(5)中
  7. f(5) = f(4)+f(3),此时,f(4)重复第6步过程得到值后被弹出,f(3)重复第5步过程得到值后被弹出,计算出f(5)的值并将f(5)弹出,同时切换到f(5)的上一个节点,即f(6)中
  8. 重复上述过程直至求出结果

总结:

​ 在整个分析过程中,主要运用到了栈和上下文切换的概念,从分析过程中我们可以了解到,针对fib(7)函数,栈中最多创建了7个内存空间,所以,斐波那契数列的空间复杂度为O(n)。

动态规划(Dynamic Programing)

以上述的过程,我们在计算f(7)时,会计算好多次f(3),我们现在要考虑:在第一次计算完f(3)后,能不能将它保存起来,当再遇到f(3)后,能不能直接得到f(3)的值,而不是通过再将f(3)以f(3)=f(2)+f(1)的计算方式得到f(3)的值

我们将这种思维称作DP(Dynamic Programing)算法,它的核心思路是:能复用的尽量去复用,而不是去计算,通过创建一个数组,将已经计算好的填入进去,方便以后调用

斐波那契数列代码改进:

import numpy as np
def fib(n):
	 tmp = np.zeros(n)
	 tmp[0] = 1
	 tmp[1] = 1
	 for i in range(2,n):
	 	tmpi = tmp[i-2] + tmp[i-1]
	 return tmp[n-1]

优点:它的时间复杂度为O(n),空间复杂度为O(n),时间复杂度得到了优化

缺点:浪费内存空间,当我们在计算f(7)时,只需要知道fib(6)和fib(5)的值即可,但此时fib(1)~fib(4)依然各占据着一份内存空间

改进思路:只让有关的函数占用内存,例如计算fib(7)时,我们只给fib(6)和fib(5)腾出内存空间来

改进代码:

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

由改进后的代码来看,空间中只保存了a,b,c三个变量,所以改进后的时间复杂度为O(n),而空间复杂度为O(1)

思考:

  1. 怎么在O(1)的时间复杂度下计算fib(n) (提示:通项公式,如下)

在这里插入图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值