动态规划(DP)基础(一)
1、动态规划简介
按照MIT算法课6.006中的说法,动态规划是一种用空间换时间的策略,即DP=recursion+memorization。本系列DP博客将以MIT算法课6.006中的实例为基础,以初学者的视角对一些特别且有价值的实例进行算法分析与代码实现。
2、一个简单例子——斐波那契数列
没有什么比斐波那契数列更适合初学者学习以入门动态规划。动态规划可能是很多初学者入门递归算法的重要例子,下面的代码给出了基于python的最简洁的斐波那契数列递归算法。
def Fibonacci(i):
if (i == 1) | (i == 2):
return 1
return Fibonacci(i - 1) + Fibonacci(i - 2) # 递归地调用函数自身,直至i=2或i=1结束调用
简单分析上述算法,不难发现其算法复杂度为(求斐波那契数列第n位的值):
θ ( 2 n 2 ) \theta(2^{\frac{n}{2}}) θ(22n)
对于指数时间而言,其增长是灾难式的。这也是为什么动态规划能有如次神奇的魔力与广阔的应用空间。
要进行动态规划分析,最好的方法之一就是建立递归树模型,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JE6geTCs-1627120273918)(F:\Sixpence Project\DP-PY\斐波那契递归树.png)]
从上图中我们不难发现,在第三层中fib(n-3)被重复计算了两次,在后续的分支中,类似的重复计算也一直在发生以至于大量的程序运行时间被浪费在了“重复造轮子”而不是真正有效的计算中。而动态规划的解决思路就是设置一个字典或列表,使已经计算过的节点值被存放在字典或列表中。在调用时首先读取字典和列表,若值存在则直接返回;否则则进行递归计算并把得到的值存放在字典中。下面的代码给出了一种基于字典的斐波那契数列递归算法。
def FibonacciDP(i