Answers:
动态编程很有用,因为您的递归算法会发现自己多次遇到相同的情况(输入参数)。从递归算法到动态编程的一般转换是称为备忘录,其中有一个表存储由递归过程计算过的所有结果。在已使用的一组输入上调用递归过程时,仅从表中获取结果。这将递归斐波那契减少为迭代斐波那契。
动态编程可以更加智能,可以应用更具体的优化。例如,有时无需在任何给定时间将整个表存储在内存中。
如果您只是想加快递归算法的速度,那么记忆就足够了。这是一种存储函数调用结果的技术,以便将来使用相同参数的调用可以仅重用结果。这适用于(且仅当)您的功能时
当(且仅当)一次又一次使用相同的参数调用该函数时,它将节省您的时间。流行的例子包括斐波那契数的递归定义,即
如果天真地求值,通常以指数形式调用。有了备注,始终已经由计算出来,因此仅剩下线性数量的呼叫。˚F (Ñ )˚F (Ñ + 1 )
请注意,与之相反,对于诸如合并排序之类的算法而言,记忆几乎是无用的:通常很少(如果有的话)部分列表是相同的,而相等检查则很昂贵(排序仅稍微贵一点!)。
在实际的实现中,如何存储结果对性能至关重要。使用哈希表可能是显而易见的选择,但可能会破坏局部性。如果您的参数是非负整数,则数组是很自然的选择,但如果仅使用某些条目,则可能会导致巨大的内存开销。因此,记忆是效果与成本之间的折衷。它是否有回报取决于您的特定情况。
动态编程完全是另一回事。适用于财产问题
当人们引用Bellman的“最优性原理”时,通常(隐式)暗示这一点。
现在,这只是描述了一类的问题,可以通过某种递归来表示。对这些内容的评估(通常)是有效的,因为可以应用备忘录来产生很大的效果(见上文);通常,较小的子问题是许多较大问题的一部分。流行的示例包括编辑距离和Bellman-Ford算法。