动态规划 (DP) 中的重叠子问题是啥?
Posted
技术标签:
【中文标题】动态规划 (DP) 中的重叠子问题是啥?【英文标题】:What are overlapping subproblems in Dynamic Programming (DP)?动态规划 (DP) 中的重叠子问题是什么? 【发布时间】:2021-02-06 11:33:00 【问题描述】:问题必须具备两个关键属性才能使动态规划适用:最佳子结构和重叠子问题[1]。对于这个问题,我们将只关注后一个属性。
重叠子问题有多种定义,其中两种是:
如果一个问题可以分解成可以重复使用多次的子问题或该问题的递归算法一遍又一遍地解决相同的子问题,而不是总是生成新的子问题 [2]. 要应用动态规划,优化问题必须具备的第二个要素是子问题的空间必须“小”,即问题的递归算法一遍又一遍地解决相同的子问题,而不是总是生成新的子问题(CLRS 的算法简介)如果找到解决方案涉及多次解决相同的子问题,这两个定义(以及互联网上的许多其他定义)似乎都归结为具有重叠子问题的问题。换句话说,在寻找原始问题的解决方案的过程中,有许多小的子问题被计算了很多次。一个经典的例子是斐波那契算法,很多例子用来让人们理解这个属性。
直到几天前,生活还很美好,直到我发现 Kadane 的算法让我质疑重叠子问题的定义。这主要是因为人们对它是否是DP算法有不同的看法:
Dynamic programming aspect in Kadane's algorithm Is Kadane's algorithm consider DP or not? And how to implement it recursively? Is Kadane's Algorithm Greedy or Optimised DP? Dynamic Programming vs Memoization (see my comment)有人不认为 Kadane 的算法是 DP 算法的最令人信服的原因是每个子问题在递归实现[3] 中只会出现并被计算一次,因此它不需要重叠子问题属性。然而,网上很多文章都认为 Kadane 的算法是一种 DP 算法,这让我对重叠子问题的理解首先产生了疑问。
人们似乎对重叠子问题属性的解释不同。用斐波那契算法等简单问题很容易看出这一点,但是一旦你介绍了 Kadane 算法,事情就会变得非常不清楚。如果有人能提供进一步的解释,我将不胜感激。
【问题讨论】:
我认为您不必过分关注给定算法是否符合“动态编程”的条件。 “动态编程”作为设计算法的范例很有帮助。作为现有算法的标签,它没有用处。您以斐波那契数列为例。许多人会不同意仅将前两个值保留在内存中的斐波那契实现是否符合“动态编程”的条件。 【参考方案1】:您已经阅读了很多关于此的内容。我唯一要补充的是:
Kadane 算法中的重叠子问题在这里:
max_subarray = max( 从 i=1 到 n [ max_subarray_to(i) ] )
max_subarray_to(i) = max(max_subarray_to(i-1) + array[i], array[i])
如您所见,max_subarray_to() 对每个 i 计算两次。 Kadane 的算法记住了这些,将其从 O(n2) 变为 O(n)
...但正如@Stef 所说,你怎么称呼它并不重要,只要你理解它。
【讨论】:
我觉得你让我大吃一惊!许多人无法证明 Kadane 算法的递归关系使得重叠子问题变得明显。我认为在大多数示例中max_subarray_to
被指定但从未指定max_subarray
,所以谢谢!所以我质疑的重叠子问题属性确实是正确的,但是我没有看到在 Kadane 的算法中如何多次重新评估子问题。
我认为这不是 DP 精神中的重叠子问题,这只是程序员愚蠢地滥用递归而不是存储 max_subarray_to
的返回值。考虑通过平方你通常做类似t = pow(x, n/2); return t*t;
的事情来求幂。但我可以做到return pow(x,n/2)*pow(x,n/2)
,这个 DP 还是只是我在做显而易见的事情并存储递归调用的返回值?我会说是后者。如果在没有记忆的情况下递归实现,真正的 DP 算法将具有 expo 运行时。 IMO,这只是强制定义。以上是关于动态规划 (DP) 中的重叠子问题是啥?的主要内容,如果未能解决你的问题,请参考以下文章