五大常用算法(二) 动态规划算法
一、算法定义
假设当你正在使用适当的输入数据进行一些计算。你在每个实例中都进行了一些计算,以便得到一些结果。当你提供相同的输入时,你不知道会有相同的输出,这就导致了你之前计算某些结果的宝贵时间被浪费掉了。你可以通过保存之前的计算结果去轻易地解决这个问题。比如通过使用恰当的数据结构等。
现在通过分析这个问题,我们可以将新的输入(或者不在数据结构中的输入)与其对应的输出存储下来。或者在字典中查找输入并返回相应的输出结果。这样当你进行一些计算时,你可以检查数据结构中是否存在该输入,如果数据输入存在的话就可以直接获得结果,我们将与这种方法相关的技巧称作 动态规划 。
二、详解动态规划
简而言之,我们可以说动态规划主要用来解决一些希望找到问题最优解的优化问题。
一种可以用动态规划解决的情况就是会有反复出现的子问题,然后这些子问题还会包含更小的子问题。相比于不断尝试去解决这些反复出现的子问题,动态规划会尝试一次解决更小的子问题。之后我们可以将结果输出记录在表格中,我们在之后的计算中可以把这些记录作为问题的原始解。
举个例子,如斐波那契数列0,1,1,2,3,5,8,13,…有着一个相当简单的描述方式,它的每个数字都与前两个紧邻的数字相关。如果 F(n) 是第 n 个数字,那么我们会有 F(n) = F(n-1) + F(n-2)。这个在数学上称作*递归方程*或者*递推关系*。为了计算后面的项,它需要前面项的计算结果作为输入。可参考本人随笔:https://www.cnblogs.com/john1015/p/12909898.html
大多数动态规划问题都能被归类成两种类型:
- 优化问题
优化问题是希望你选择一个可行的解决方案,以便最小化或最大化所需函数的值。
- 组合问题
组合问题是希望你弄清楚做某事方案的数量或某些事件发生的概率。
解决方案的对比:自上而下 或者 自下而上,
以下是两种不同的动态规划解决方案:
- 自下而上:你从最顶端开始不断地分解问题,直到你看到问题已经分解到最小并已得到解决,之后只用返回保存的答案即可。这叫做记忆存储(*Memoization*)。
- 自下而上:你可以直接开始解决较小的子问题,从而获得最好的解决方案。在此过程中,你需要保证在解决问题之前先解决子问题。这可以称为表格填充算法(*Tabulation,*table-filling algorithm**)。
至于迭代和递归与这两种方法的关系,自下而上用到了迭代技术,而自上而下用到了 递归技术。
使用递归算法计算斐波那契数列之所以慢,是因为它重复的计算了相同的数据。
三、应用例子
本人随笔《剑指offer 变态跳台阶》:https://www.cnblogs.com/john1015/p/12916468.html