力扣斐波那契数列 509
虽然这是一道简单题,但是对于我这个新手来说,有很多可以学习的算法改进的思路。拿到这个题的时候,第一想法就是暴力递归。
#暴力递归
def fib(self, n: int) -> int:
if n==0:
return 0
elif n==1:
return 1
else:
return self.fib(n-1)+self.fib(n-2)
但是。。。
暴力递归算法会重复计算很多步骤,按照递归算法时间复杂度的算法=子问题的个数*子问题所占用的时间 那么暴力递归算法时间复杂度为O(2^n)。例如:
求
蓝色虚框内的算法都会重复一遍。然后我就看了大家的题解,主要是从这篇题解中学习的:参考题解
因此要对暴力递归算法进行改进,把部分重复的值用字典存起来,用的时候调用,就会减少重复计算的步骤。这种字典或者解决问题的方式叫做备忘录。
备忘录的递归算法(只写核心部分)–严格意义上,这已经不是递归了,没有对自己函数的调用,应该是递推:
dic={0:0,1:1}
for i in range(2,n+1):
dic[i]=dic[i-1]+dic[i-2]
return dic[n]
时间复杂度为O(n)。但是这样,还是存在一个问题,因为我们要求解的值f(n),显然只和f(n-1)和f(n-2)有关,那么其他的更小项对应的值只会用到一次,占据了空间。
所以,最好在用完之后就delete掉,这样的话,空间复杂度就可以得到优化,这个过程叫做状态压缩。
状态压缩的dp算法:
m=0
p=0
q=1
for i in range(3,n+1):
p=q
q=p+m
m=p
return p+q
状态压缩之后空间复杂度变为O(1)。结束。