Answers:
有关Programming.Guide的相关文章:动态编程vs记忆和列表
记忆和动态编程之间有什么区别?
记忆是一个描述优化技术的术语,您可以在其中缓存先前计算的结果,并在再次需要相同的计算时返回缓存的结果。
动态编程是一种迭代解决递归性质问题的技术,适用于子问题的计算重叠的情况。
动态编程通常使用制表来实现,但也可以使用备注来实现。因此,您可以看到,任何一个都不是另一个的“子集”。
一个合理的后续问题是:制表(典型的动态编程技术)和备注之间有什么区别?
当使用制表法解决动态编程问题时,您将解决“ 自下而上 ” 的问题,即首先解决所有相关的子问题,通常是填写n维表。根据表中的结果,然后计算“顶部” /原始问题的解决方案。
如果使用备忘录来解决问题,则可以通过维护已经解决的子问题的图来解决。从“先自上而下 ”的意义上讲,您是“自上而下”的(通常向下递归以解决子问题)。
此处的幻灯片很好(链接现已消失,但幻灯片仍然很好):
- 如果必须至少一次解决所有子问题,那么自下而上的动态编程算法通常比自上而下的固定算法要好一个常数。
- 没有递归开销,而维护表的开销更少
- 对于某些问题,可以利用动态编程算法中的常规表访问模式来进一步减少时间或空间需求
- 如果根本不需要解决子问题空间中的某些子问题,则记忆化解决方案的优点是仅解决那些绝对需要的子问题
其他资源:
动态编程是一种算法范式,它通过将给定的复杂问题分解为子问题来解决,并存储子问题的结果以避免再次计算相同的结果。
http://www.geeksforgeeks.org/dynamic-programming-set-1/
记忆化是跟踪先前解决的解决方案的一种简便方法(通常以哈希键值对的形式实现,这与通常基于数组的制表相反),这样在再次遇到它们时就不会重新计算它们。它可以在自下而上或自上而下的方法中使用。
请参阅有关记忆与制表的讨论。
因此,动态编程是一种通过解决递归关系/递归并通过列表或备注存储先前找到的解决方案来解决某些类别问题的方法。记忆化是一种跟踪先前解决的问题的解决方案的方法,可以与对给定输入集具有唯一确定性解决方案的任何功能一起使用。
动态编程通常被称为记忆化!
记忆化是自上而下的技术(通过分解解决给定的问题),动态编程是自下而上的技术(从琐碎的子问题开始解决给定的问题)
DP通过从基本案例开始找到解决方案,然后向上解决。DP解决了所有子问题,因为它自下而上
与“记忆化”不同,“记忆化”仅解决所需的子问题
DP具有将指数时间的蛮力解转换为多项式时间算法的潜力。
DP可能更有效率,因为它具有迭代性
相反,由于递归,记忆化必须支付(通常是很大的)开销。
更简单地说,“记忆化”使用自顶向下的方法来解决问题,即从核心(主要)问题开始,然后将其分解为子问题,并类似地解决这些子问题。在这种方法中,相同的子问题可能会多次发生并消耗更多的CPU周期,因此会增加时间复杂度。而在动态编程中,相同的子问题不会被多次解决,但是先前的结果将用于优化解决方案。
(1)从概念上来说,记忆和DP 实际上是同一回事。因为:考虑DP的定义:“重叠子问题”“和最佳子结构”。备注完全具备这些2。
(2)记忆是DP,具有递归深度的堆栈溢出风险。DP自下而上没有此风险。
(3)记住需要一个哈希表。这样就增加了空间,并增加了一些查找时间。
所以要回答这个问题:
- 从概念上讲,(1)表示它们是同一件事。
-考虑到(2),如果真的需要,备忘录是DP的子集,从某种意义上说,备忘录可以解决的问题可以由DP解决,但是DP可以解决的问题可能无法通过备忘录解决(因为它可能会堆栈溢出)。
-考虑到(3),它们的性能差异很小。
问题:
您正在爬楼梯。它需要n步才能到达顶部。
每次您可以爬1或2步。您可以通过几种不同的方式登顶?
带记忆的递归
通过这种方式,我们在备忘录数组的帮助下修剪(从树或灌木中去除多余的材料)递归树,并将递归树的大小减小到nn。
public class Solution {
public int climbStairs(int n) {
int memo[] = new int[n + 1];
return climb_Stairs(0, n, memo);
}
public int climb_Stairs(int i, int n, int memo[]) {
if (i > n) {
return 0;
}
if (i == n) {
return 1;
}
if (memo[i] > 0) {
return memo[i];
}
memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo);
return memo[i];
}
}
动态编程
正如我们所看到的,该问题可以分解为子问题,并且包含最优子结构属性,即可以根据子问题的最优解有效地构造其最优解,我们可以使用动态编程来解决该问题。
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
在动态编程中,
在背诵中