繁体   English   中英

何时使用自下而上 DP 何时使用自上而下 DP

[英]when to use bottom-up DP and when to use top-down DP

我已经学习了两种DP方式,但我现在很困惑。 不同情况下我们如何选择? 而且我发现在大多数情况下,自上而下对我来说更自然。 谁能告诉我如何做出选择。

PS:我已经阅读了这篇较旧的帖子,但仍然感到困惑。 需要帮忙。 不要将我的问题视为重复。 我已经提到它们是不同的。 我希望知道如何选择以及何时从自上而下或自下而上的方式考虑问题。

为了简单起见,我将根据我对一些来源的总结进行解释

  1. 自上而下:看起来像: a(n) = a(n-1) + a(n-2) 使用这个等式,您可以a调用函数本身来使用大约 4-5 行代码来实现。 正如您所说,它的优势对大多数开发人员来说是非常直观的,但它会花费更多的空间(内存堆栈)来执行。
  2. 自下而上:首先计算a(0)然后a(1) ,并将其保存到某个数组(例如),然后连续保存a(i) = a(i-1) + a(i-2) . 使用这种方法,您可以显着提高代码的性能。 使用 big n ,您可以避免堆栈溢出。

一个稍长的答案,但我试图解释我自己的动态规划方法以及在解决这些问题后我所理解的内容。 我希望未来的用户觉得它有用。 请随时发表评论和讨论:

在考虑动态规划问题时,自上而下的解决方案更为自然。 您从最终结果开始,并尝试找出实现目标的方法。 例如,对于 fib(n),我们知道我们只能通过 fib(n-1) 和 fib(n-2) 到达这里。 所以我们再次递归调用该函数来计算这两种情况的答案,它会越来越深入到树中,直到达到基本情况。 然后将答案建立起来,直到弹出所有堆栈并获得最终结果。

为了减少重复计算,我们使用缓存来存储新结果并在函数尝试再次计算时返回它。 所以,如果你想象一棵树,函数调用不必一直向下到树叶,它已经有了答案,所以它会返回它。 这称为记忆,通常与自上而下的方法相关联。

现在,我认为对于自下而上的方法来说,重要的一点是您必须知道构建最终解决方案的顺序。 在自上而下的情况下,您只是将一件事分解成许多,但在自下而上的情况下,您必须知道从一个级别到下一个级别的计算需要涉及的状态的数量和顺序。 在一些更简单的问题中(例如 fib(n)),这很容易看出,但对于更复杂的情况,它并不自然适用。 我通常遵循的方法是自上而下思考,将最终案例分解为以前的状态,并尝试找到一种模式或顺序,然后能够将其重新构建。

关于何时选择其中任何一个,我建议使用上述方法来确定状态如何相互关联以及如何构建。 您可以通过这种方式发现的一个重要区别是真正需要多少计算以及多少计算可能只是多余的。 在自下而上的情况下,您必须在进入下一个之前填充整个级别。 然而,在自上而下的情况下,如果不需要,可以跳过整个子树,这样可以节省很多额外的计算。

因此,选择显然取决于问题,但也取决于状态之间的相互关系。 通常情况下,建议使用自下而上,因为与递归方法相比,它可以节省堆栈空间。 但是,如果您觉得递归不太深但很宽并且可能会通过表格化导致大量不必要的计算,那么您可以使用记忆化的自顶向下方法。

例如,在这个问题中: https ://leetcode.com/problems/partition-equal-subset-sum/,如果你看到讨论,提到自上而下比自下而上快,基本上,二进制带有缓存的树方法与背包自下而上的构建。 我把它留作理解状态之间关系的练习。

对于时间和空间复杂度方面的许多问题,自下而上和自上而下的 DP 方法是相同的。 不同之处在于,自下而上更快一点,因为您不需要递归的开销,而且,是的,自上而下更直观和自然。

但是,自上而下方法的真正优势在于一些小的任务集,您不需要为所有较小的子任务计算答案。 在这种情况下,您可以降低时间复杂度。

例如,您可以使用带记忆的自上而下方法来查找第 N 个斐波那契数,其中序列定义为 a[n]=a[n-1]+a[n-2] 所以,您有两个 O( N) 计算它的时间(我不与 O(logN) 解决方案进行比较来找到这个数字)。 但是看看序列 a[n]=a[n/2]+a[n/2-1] 和一些小 N 的边缘情况。在 botton up 方法中你不能比 O(N) 更快自上而下的算法将以复杂度 O(logN) 工作(或者可能是某种多对数复杂度,我不确定)

为了补充以前的答案,

  1. 最佳时间:
 if all sub-problems need to be solved → bottom-up approach else → top-down approach
  1. 最佳空间:自下而上的方法

Nikhil_10 链接的问题(即https://leetcode.com/problems/partition-equal-subset-sum/ )不需要解决所有子问题。 因此,自上而下的方法更为优化。

如果您喜欢自上而下的自然模式,那么在您知道可以实现它的情况下使用它。 自下而上比自上而下更快。 有时自下而上更容易,而大多数时候自下而上很容易。 根据您的情况做出决定。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM