记忆和动态规划的区别是什么?我认为动态规划是记忆的一个子集。对吗?
当前回答
动态规划是对普通递归算法的优化,它考虑所有输入的组合以提供最合适的答案。这种方法有一个缺点,它的时间复杂度很高。使用记忆法可以使记忆更有效。它将存储子问题的每个输出,并在该算法再次尝试解决该子问题时直接给出答案。这可以使算法具有多项式的时间复杂度。
其他回答
动态规划是对普通递归算法的优化,它考虑所有输入的组合以提供最合适的答案。这种方法有一个缺点,它的时间复杂度很高。使用记忆法可以使记忆更有效。它将存储子问题的每个输出,并在该算法再次尝试解决该子问题时直接给出答案。这可以使算法具有多项式的时间复杂度。
从维基百科:
记忆有关
在计算中,记忆是一种主要使用的优化技术 通过函数调用来加速计算机程序,避免重复 对先前处理过的输入的结果的计算。
动态规划
在数学和计算机科学中,动态规划是一种方法 把复杂的问题分解成更简单的问题 子问题。
当把一个问题分解成更小/更简单的子问题时,我们经常会不止一次遇到相同的子问题——所以我们使用Memoization来保存以前的计算结果,这样我们就不需要重复它们了。
动态编程经常遇到使用内存是有意义的情况,但您可以使用任何一种技术而不必使用另一种技术。
想想两种方法,
我们把大问题分解成小问题——自顶向下的方法。 我们从最小的子问题开始,到达更大的问题——自下而上的方法。
在Memoization中,我们使用(1.),我们将每个函数调用保存在缓存中,并从那里进行回调。它有点昂贵,因为它涉及到递归调用。
在动态规划中,我们使用(2.)来维护一个表,通过使用保存在表中的数据(通常称为dp-table)自底向上解决子问题。
注意:
两者都适用于具有重叠子问题的问题。 由于递归函数调用期间涉及的开销,内存相对于DP执行得较差。 渐近时间复杂度保持不变。
在动态规划中,
没有递归的开销,维护表的开销也更少。 表访问的规则模式可用于减少时间或空间需求。
在记忆中,
有些子问题不需要解决。
我想举个例子;
问题:
你正在爬楼梯。到达顶端需要n步。 每次你可以爬1或2级台阶。有多少不同的方式 你能爬到山顶吗?
带记忆的递归
通过这种方式,我们在memo数组的帮助下修剪(从树或灌木中去除多余的材料)递归树,并将递归树的大小减小到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];
}
}
示例摘自https://leetcode.com/problems/climbing-stairs/