【问题标题】:Difference between dynamic programming and recursion动态规划和递归的区别
【发布时间】:2020-11-20 01:24:38
【问题描述】:

动态规划递归有什么区别? 我在 geeksforgeeks 教程点和 Wikipedia 中浏览了许多文章,但在我看来两者是相同的。

你能用斐波那契数列的例子解释一下动态规划和递归之间的区别吗?

【问题讨论】:

  • 递归是一种“语言特性”,可用于实现动态编程的“技术”以及其他用途。
  • 动态编程(“programming”这里的意思是“planning”)是一种优化方法,可以使用recursion with memoization来实现。它也可以使用其他方法来实现。看看 Cormen 等人。 book。 Geeksforgeeks 是一种质量很差的资源,最好避免使用。
  • 递归是函数调用自身的时候。动态编程是一种“技术”,您可以通过填写表格来解决某些子问题,从而解决某些问题。填充该表可能会使用递归。
  • 那么动态规划是递归的一种应用?
  • 动态规划 (DP) 是一种用于解决某些类型问题的技术。这些问题有两个性质,最优子结构和重叠子问题。 DP技术分为两种:自顶向下和自底向上。自上而下使用从n 开始并进入基本情况的递归,而自下​​而上从基本情况开始并进入n

标签: recursion dynamic-programming fibonacci


【解决方案1】:

计算斐波那契数列中的项非常容易,因为实际上您只需要记住fib(n-2)fib(n-1) 即可计算fib(n)。因为它非常简单,所以任何算法都将非常简单,所以这个例子模糊了不同动态编程范式之间的细微差别。话虽如此,你提到的维基百科页面对斐波那契有很好的解释:https://en.wikipedia.org/wiki/Dynamic_programming#Fibonacci_sequence

如果函数在执行过程中调用自身,则称为递归函数。

可以使用或不使用递归来实现动态规划算法。

动态规划的核心是利用以下两个事实来编写算法:

  1. 问题的解决方案可以分解为子问题的解决方案;
  2. 当问题P 的最优解S 分解为s1s2、...到子问题p1p2、...、然后s1 的解时, s2, ... 都是各自子问题的最优解。

请注意,这两个事实并非适用于所有问题。只有当这两个事实适用时,问题才适合动态规划。

一个简单的例子是找到从 A 点到 B 点的最短路径:如果从 A 到 B 的最短路径经过 C 点,那么它构成的从 A 到 C 和从 C 到 B 的两半也是最短路径。

在大多数情况下,您可以进行递归调用来解决子问题。但是“幼稚”的递归方法很容易导致指数算法,因为级联“为了解决这个问题,我需要解决这两个(或更多)子问题”,这可能会迅速增加您必须解决的问题数量解决。这是一个斐波那契的例子:

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

在这里,我们必须计算 16 个词才能找到 fib(5)。但请注意,总共只有 6 个不同的术语。当然,通过避免一次又一次地重复相同的计算,我们可以提高效率。

为避免这种情况,动态规划算法通常相当于用子问题的解决方案填充数组。一旦您确定了子问题列表和数组,可能没有太多动力去“自上而下”进行递归调用,从最大的问题开始,然后依次将其分解为较小的子问题。相反,您可以从最琐碎的问题开始“自下而上”地填充数组,然后使用这些问题来解决更复杂的问题,直到您解决了最初想要解决的问题。在斐波那契数列的情况下,您可能会得到以下代码:

int f[n+1];
f[0] = 0;
f[1] = 1;
for (int k = 2; k <= n; k++)
  f[k] = f[k-2] + f[k-1];
return f[n];

但是,在斐波那契数列的情况下,您只需要随时记住最后两个术语,因此无需使用从 fib(0)fib(n) 的所有术语填充整个数组,您只需保留两个变量(或大小为 2 的数组)与前两个结果。可以说这仍然是动态编程,尽管它最终只是一个循环,按顺序计算序列的项,而且很难看到任何关于它的“动态”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 2011-04-05
    • 2014-06-26
    • 2013-11-14
    • 2012-07-10
    • 2011-11-09
    • 2012-09-20
    相关资源
    最近更新 更多