动态编程:自上而下与自下而上的比较

时间:2012-12-05 20:15:18

标签: dynamic-programming

你能指点一些动态编程问题陈述,其中自下而上比自上而下更有利吗? (即简单的DP工作更自然,但记忆难以实现?)

我发现记忆的递归更加容易,并希望解决自下而上是更好/可能唯一可行方法的问题。

我理解理论上两者都是等价的,所以即使是易于实施的东西也算是一种好处。

2 个答案:

答案 0 :(得分:4)

根据手头的问题,您将自下而上应用memoization或自上而下的递归和memoization。

例如,如果必须找到路径图的最小权重无关路径,则必须使用自底向上方法,因为必须解决所有可能的子问题。

但是如果你必须解决背包问题,你可能想要使用递归自上而下的memoization,因为你必须解决有限数量的子问题。自下而上接近背包问题将导致算法解决许多原始子问题中未使用的冗余问题。

答案 1 :(得分:0)

决定使用哪种算法时需要考虑的两件事

  1. 时间复杂性。两种方法通常具有相同的时间复杂度,但是因为for循环比递归函数调用便宜,所以如果在机器时间中测量,自下而上可以更快。
  2. 空间复杂性。 (自上而下不考虑额外的调用堆栈分配)通常两种方法都需要为所有子解决方案构建一个表,但自下而上是遵循拓扑顺序,辅助空间的成本有时可以减少到问题的大小直接依赖。例如:fibonacci(n) = fibonacci(n-1) + fibonacci(n-2),我们只需要存储过去的两次计算
  3. 话虽如此,自下而上并不总是最佳选择,我将尝试用例子说明:

    1. (由@Nikunj Banka提及)自上而下只能解决您的解决方案使用的子问题,而自下而上可能会浪费时间来处理冗余子问题。一个愚蠢的例子是0-1 knapsack有1个项目......运行时间差是O(1)对O(重量)
    2. 您可能需要执行额外的工作才能获得自下而上的拓扑订单。在Longest Increasing Path in Matrix中,如果我们想在依赖之后做子问题,我们必须按降序对矩阵的所有条目进行排序,这是DP之前的额外nmlog(nm)预处理时间