记忆和动态规划的区别是什么?我认为动态规划是记忆的一个子集。对吗?


当前回答

想想两种方法,

我们把大问题分解成小问题——自顶向下的方法。 我们从最小的子问题开始,到达更大的问题——自下而上的方法。

在Memoization中,我们使用(1.),我们将每个函数调用保存在缓存中,并从那里进行回调。它有点昂贵,因为它涉及到递归调用。

在动态规划中,我们使用(2.)来维护一个表,通过使用保存在表中的数据(通常称为dp-table)自底向上解决子问题。

注意:

两者都适用于具有重叠子问题的问题。 由于递归函数调用期间涉及的开销,内存相对于DP执行得较差。 渐近时间复杂度保持不变。

其他回答

动态规划是对普通递归算法的优化,它考虑所有输入的组合以提供最合适的答案。这种方法有一个缺点,它的时间复杂度很高。使用记忆法可以使记忆更有效。它将存储子问题的每个输出,并在该算法再次尝试解决该子问题时直接给出答案。这可以使算法具有多项式的时间复杂度。

动态规划是一种求解给定问题的算法范式 将复杂问题分解为子问题并存储结果 以避免再次计算相同的结果。

http://www.geeksforgeeks.org/dynamic-programming-set-1/

记忆是一种跟踪以前解决的解决方案的简单方法(通常实现为哈希键值对,而不是通常基于数组的制表),这样当它们再次遇到时就不会重新计算。它可以在自底向上或自顶向下的方法中使用。

请参阅关于记忆和制表的讨论。

动态规划是一种通过求解递归关系/递归并通过制表或记忆存储先前找到的解来解决某些类型问题的方法。记忆是一种跟踪以前解决问题的解决方案的方法,可以与任何对于给定输入集具有唯一确定性解决方案的函数一起使用。

这是一个记忆和DP从斐波那契数问题写在Java的例子。

这里的动态编程不涉及递归,因为它不受执行堆栈的限制,所以结果更快,可以计算出更高的值。

public class Solution {

 public static long fibonacciMemoization(int i) {
    return fibonacciMemoization(i, new long[i + 1]);
 }

 public static long fibonacciMemoization(int i, long[] memo) {
    if (i <= 1) {
        return 1;
    }
    if (memo[i] != 0) {
        return memo[i];
    }
    long val = fibonacciMemoization(i - 1, memo) + fibonacciMemoization(i - 2, memo);
    memo[i] = val;
    return val;
 }

 public static long fibonacciDynamicPrograming(int i) {
    if (i <= 1) {
        return i;
    }
    long[] memo = new long[i + 1];
    memo[0] = 1;
    memo[1] = 1;
    memo[2] = 2;
    for (int j = 3; j <= i; j++) {
        memo[j] = memo[j - 1] + memo[j - 2];
    }
    return memo[i];
 }

 public static void main(String[] args) {
    System.out.println("Fibonacci with Dynamic Programing");
    System.out.println(fibonacciDynamicPrograming(10));
    System.out.println(fibonacciDynamicPrograming(1_000_000));

    System.out.println("Fibonacci with Memoization");
    System.out.println(fibonacciMemoization(10));
    System.out.println(fibonacciMemoization(1_000_000)); //stackoverflow exception
 }
}

从维基百科:

记忆有关

在计算中,记忆是一种主要使用的优化技术 通过函数调用来加速计算机程序,避免重复 对先前处理过的输入的结果的计算。

动态规划

在数学和计算机科学中,动态规划是一种方法 把复杂的问题分解成更简单的问题 子问题。

当把一个问题分解成更小/更简单的子问题时,我们经常会不止一次遇到相同的子问题——所以我们使用Memoization来保存以前的计算结果,这样我们就不需要重复它们了。

动态编程经常遇到使用内存是有意义的情况,但您可以使用任何一种技术而不必使用另一种技术。

(1)从概念上讲,记忆和DP其实是一回事。因为:考虑DP的定义:“重叠子问题”和“最优子结构”。记忆完全具备这两点。

(2)在递归较深的情况下,记忆是DP方法,存在栈溢出风险。DP自下而上没有这种风险。

(3)记忆需要一个哈希表。额外的空间和查找时间。

为了回答这个问题:

-从概念上讲,(1)意味着它们是一样的东西。

-考虑(2),如果你真的想,记忆化是DP的一个子集,从某种意义上说,可以通过记忆化解决的问题可以通过DP解决,但是可以通过DP解决的问题可能无法通过记忆化解决(因为它可能会堆栈溢出)。

把(3)考虑在内,它们在性能上有微小的差异。