分治算法和动态规划算法的区别是什么?这两个术语有什么不同?我不明白它们之间的区别。

请举一个简单的例子来解释两者之间的区别,以及它们相似的理由。


当前回答

我认为分治法是递归方法,动态规划是表填充。

例如,归并排序是一种分治算法,因为在每一步中,您将数组分成两部分,递归地在两部分上调用归并排序,然后合并它们。

Knapsack是一种动态规划算法,因为您正在填充表示整个背包子问题的最优解的表。表中的每一项都对应于给定物品1-j的袋子中所能携带的最大重量w。

其他回答

分治法在每一级递归中涉及三个步骤:

把问题分成子问题。 通过递归求解子问题来克服子问题。 将子问题的解合并到原问题的解中。 这是一种自顶向下的方法。 它在子问题上做更多的工作,因此有更多的时间 消费。 如。斐波那契数列的第n项可以用O(2^n)个时间复杂度计算。

动态规划包括以下四个步骤: 1. 描述最优解的结构。 2. 递归地定义最优解的值。 3.计算最优解的值。 4. 从计算的信息构造一个最优解。

这是一种自底向上的方法。 由于我们使用了之前计算的值,而不是再次计算,因此比分治算法花费的时间更少。 如。斐波那契数列的第n项可以用O(n)个时间复杂度来计算。

为了便于理解,让我们将分而治之视为一种暴力解决方案,并将其优化视为动态规划。 注意:具有重叠子问题的分治算法只能用dp进行优化。

分而治之 它们分解成互不重叠的子问题 示例:阶乘数,即fact(n) = n*fact(n-1)

fact(5) = 5* fact(4) = 5 * (4 * fact(3))= 5 * 4 * (3 *fact(2))= 5 * 4 * 3 * 2 * (fact(1))

正如我们上面看到的,没有事实(x)是重复的,所以阶乘没有重叠的问题。

动态规划 他们分成了重叠的子问题 示例:斐波那契数列,即fib(n) = fib(n-1) + fib(n-2)

fib(5) = fib(4) + fib(3) = (fib(3)+fib(2)) + (fib(2)+fib(1))

如上所述,fib(4)和fib(3)都使用fib(2)。同样的,很多fib(x)被重复。这就是为什么斐波那契有重叠的子问题。

由于DP中子问题的重复,我们可以将这些结果保存在一个表中,节省了计算量。这被称为记忆

分而治之

分而治之的工作原理是将问题划分为子问题,递归地征服每个子问题,并将这些解决方案组合起来。

动态规划

动态规划是一种解决具有重叠子问题的问题的技术。每个子问题只解决一次,每个子问题的结果存储在一个表中(通常实现为数组或哈希表),以供将来引用。这些子解可以用来获得原始解,存储子问题解的技术称为记忆。

你可能会想到DP =递归+重用

理解差异的一个经典例子是,这两种方法都可以获得第n个斐波那契数。看看麻省理工学院的材料。


分而治之法

动态规划方法

有时候在递归编程时,你会多次调用具有相同参数的函数,这是不必要的。

著名的斐波那契数列例子:

           index: 1,2,3,4,5,6...
Fibonacci number: 1,1,2,3,5,8...

function F(n) {
    if (n < 3)
        return 1
    else
        return F(n-1) + F(n-2)
}

我们运行F(5):

F(5) = F(4) + F(3)
     = {F(3)+F(2)} + {F(2)+F(1)}
     = {[F(2)+F(1)]+1} + {1+1}
     = 1+1+1+1+1

所以我们叫: 1乘以F(4) 2乘以F(3) 3乘以F(2) 2乘以F(1)

动态编程方法:如果多次调用具有相同参数的函数,则将结果保存到变量中,以便下次直接访问。迭代方法:

if (n==1 || n==2)
    return 1
else
    f1=1, f2=1
    for i=3 to n
         f = f1 + f2
         f1 = f2
         f2 = f

我们再次调用F(5):

fibo1 = 1
fibo2 = 1 
fibo3 = (fibo1 + fibo2) = 1 + 1 = 2
fibo4 = (fibo2 + fibo3) = 1 + 2 = 3
fibo5 = (fibo3 + fibo4) = 2 + 3 = 5

如您所见,每当您需要多重调用时,您只需访问相应的变量来获得值,而不是重新计算它。

顺便说一下,动态规划并不意味着将递归代码转换为迭代代码。如果需要递归代码,还可以将子结果保存到变量中。在这种情况下,这种技术被称为记忆。在我们的例子中,它是这样的:

// declare and initialize a dictionary
var dict = new Dictionary<int,int>();
for i=1 to n
    dict[i] = -1

function F(n) {
    if (n < 3)
        return 1
    else
    {
        if (dict[n] == -1)
            dict[n] = F(n-1) + F(n-2)

        return dict[n]                
    }
}

所以与分治法的关系是D&D算法依赖于递归。有些版本会出现“使用相同参数的多个函数调用问题”。搜索“矩阵链乘法”和“最长公共子序列”,寻找需要DP来改进D&D算法的T(n)的例子。

我认为分治法是递归方法,动态规划是表填充。

例如,归并排序是一种分治算法,因为在每一步中,您将数组分成两部分,递归地在两部分上调用归并排序,然后合并它们。

Knapsack是一种动态规划算法,因为您正在填充表示整个背包子问题的最优解的表。表中的每一项都对应于给定物品1-j的袋子中所能携带的最大重量w。