分治算法和动态规划算法的区别是什么?这两个术语有什么不同?我不明白它们之间的区别。
请举一个简单的例子来解释两者之间的区别,以及它们相似的理由。
分治算法和动态规划算法的区别是什么?这两个术语有什么不同?我不明白它们之间的区别。
请举一个简单的例子来解释两者之间的区别,以及它们相似的理由。
当前回答
分而治之
在此问题的解决分为以下三步: 1. 划分-划分若干个子问题 2. 征服——通过递归解决子问题来征服 3.组合-结合子问题的解决方案,以得到原问题的解决方案 递归方法 自顶向下技术 示例:归并排序
动态规划
在此问题的解决步骤如下: 1. 定义最优解的结构 2. 反复定义最优解的值。 3.用自底向上的方法求最优解的值 4. 从得到的值得到最终的最优解 非递归 自底向上技术 例子:Strassen矩阵乘法
其他回答
分而治之和动态规划的另一个区别是:
分而治之:
在子问题上做更多的工作,因此有更多的时间消耗。 分治法中子问题是相互独立的。
动态规划:
只解决一次子问题,然后将其存储在表中。 在动态规划中,子问题不是相互独立的。
分而治之:
这一范式包括三个阶段:
把这个问题分成更小的子问题 征服,即解决这些较小的子问题 结合这些子问题的解,得到最终答案。
动态规划:
DP is an optimization of recursive solutions. The primary difference it makes is that it stores the solution to sub-problems, which can later be accessed during the process of finding solutions of the remaining sub-problems. This is done so that we don't have to calculate the solution to a sub-problem every time, rather we can simply look it up the computer memory to retrieve its value, given that it has been solved earlier. We can simply add this as our base case in recursion. For example, we are solving a problem through recursion, we can store the solutions to sub-problems in an array and access them by adding the relevant code in one of our base cases in the recursive method.
DP有两种实现方式:
考虑一个问题:求x的阶乘。
制表法:我们使用自底向上的方法,也就是从最小的数一直到x,来找到解。
伪代码:
1. int array
2. for int=1, i<=x, i++
3. array[i] = array[i-1]*i
记忆法:我们使用自顶向下的方法,也就是说,我们把问题分解成更小的部分,然后解决它们,以得到最终的解决方案
伪代码:
fac():
1. int array
2. if(x==0): return 1
3. if(array[x]!=null): return array[x]
4. return array[x] = x*fac(x-1)
我假设你已经阅读了维基百科和其他关于这方面的学术资源,所以我不会重复使用任何信息。我还必须提醒,我不是计算机科学专家,但我将分享我对这些主题的理解……
动态规划
把问题分解成离散的子问题。Fibonacci序列的递归算法是动态规划的一个例子,因为它通过首先求解fib(n-1)来求解fib(n)。为了解决原来的问题,它解决了一个不同的问题。
分而治之
These algorithms typically solve similar pieces of the problem, and then put them together at the end. Mergesort is a classic example of divide and conquer. The main difference between this example and the Fibonacci example is that in a mergesort, the division can (theoretically) be arbitrary, and no matter how you slice it up, you are still merging and sorting. The same amount of work has to be done to mergesort the array, no matter how you divide it up. Solving for fib(52) requires more steps than solving for fib(2).
分而治之
在此问题的解决分为以下三步: 1. 划分-划分若干个子问题 2. 征服——通过递归解决子问题来征服 3.组合-结合子问题的解决方案,以得到原问题的解决方案 递归方法 自顶向下技术 示例:归并排序
动态规划
在此问题的解决步骤如下: 1. 定义最优解的结构 2. 反复定义最优解的值。 3.用自底向上的方法求最优解的值 4. 从得到的值得到最终的最优解 非递归 自底向上技术 例子:Strassen矩阵乘法
动态规划与分治的相似之处
在我看来,现在我可以说动态规划是分而治之的范例的扩展。
我不会把它们视为完全不同的东西。因为它们都是通过递归地将一个问题分解为两个或多个相同或相关类型的子问题,直到它们变得足够简单可以直接解决。然后将子问题的解组合起来给出原始问题的解。
那么为什么我们仍然有不同的范式名称,为什么我称动态规划为扩展。这是因为只有当问题具有一定的限制条件或先决条件时,才可以应用动态规划方法。在此基础上,动态规划利用记忆法和制表法对分治法进行了扩展。
让我们一步一步来……
动态规划先决条件/限制
正如我们刚刚发现的,为了使动态规划适用,分治问题必须具有两个关键属性:
最优子结构-最优解可以由其子问题的最优解构造 重叠子问题——问题可以分解为多次重用的子问题,或者问题的递归算法可以一遍又一遍地解决相同的子问题,而不是总是生成新的子问题
一旦满足这两个条件,我们就可以说这个分治问题可以用动态规划方法来解决。
分而治之的动态规划扩展
动态规划方法通过两种技术(记忆和制表)扩展了分而治之的方法,这两种技术都具有存储和重用子问题解决方案的目的,可以极大地提高性能。例如,斐波那契函数的朴素递归实现的时间复杂度为O(2^n),而DP解决方案只需要O(n)时间就可以完成同样的工作。
记忆(自顶向下缓存填充)是指缓存和重用先前计算结果的技术。因此,记忆fib函数看起来像这样:
memFib(n) {
if (mem[n] is undefined)
if (n < 2) result = n
else result = memFib(n-2) + memFib(n-1)
mem[n] = result
return mem[n]
}
制表(自底向上的缓存填充)与此类似,但重点是填充缓存的条目。计算缓存中的值最简单的方法是迭代。fib的制表版本是这样的:
tabFib(n) {
mem[0] = 0
mem[1] = 1
for i = 2...n
mem[i] = mem[i-2] + mem[i-1]
return mem[n]
}
你可以在这里读到更多关于记忆和制表比较的内容。
这里您应该掌握的主要思想是,由于我们的分治问题具有重叠的子问题,因此可以缓存子问题的解决方案,从而实现记忆/制表。
那么到底DP和DC有什么区别呢
既然我们现在已经熟悉了DP的先决条件和它的方法,我们就可以把上面提到的所有内容放在一张图中了。
如果你想看代码示例,你可以看看这里更详细的解释,你会发现两个算法示例:二进制搜索和最小编辑距离(Levenshtein Distance),它们说明了DP和DC之间的区别。