在整数列表中找到最常见的总和

时间:2019-05-25 02:26:40

标签: algorithm dynamic-programming

我正在尝试在整数列表中找到最常见的总和。

例如,在给定列表2 + 8 = 4 + 6 = 10 2 + 4 + 6 = 4 + 8 = 12 2 + 4 + 8 = 6 + 8 = 14的情况下,最常见的总和为10、12和14,因为它们的总和有两种:

GridView

当然,其他可能的总和仅发生一次。我知道像这样的简单列表可以被强行使用,但是我想要某种一般性提示,以了解如何解决较大列表的问题。例如,也许我可以以某种方式利用动态编程?

1 个答案:

答案 0 :(得分:2)

这是subset sum problem的变体。可以使用动态编程在时间复杂度为 O(n * sum)的伪多项式时间内完成。

重复关系

  

dp(sum,i)= dp(sum-a [i],i-1)的总和

说明

想象一下,您有一个解决方案,可以解决从0i-1的所有元素的子集进行任何求和的可能性。对于dp(sum, i - 1)的所有值,我们用sum表示。为了在构成a[i]的有效子集中包含新元素sum,必须在sum - a[i]的元素子集中为0提供至少一个解决方案到i - 1。然后,获得元素sum0的元素子集的i的方法的数量成为元素{ {1}}至sum - a[i]

实施

C ++中的自底向上实现如下:

0

该实现使用相同的动态编程解决方案。但是,它仅通过将i - 1(而不是dp(sum,i-2),dp(sum,i-3)等)保留为int mostCommonSum(const vector<int>& a) { int sum = 0; for(auto num: a) { sum += num; } vector<int> dp(sum + 1); dp[0] = 1; sum = 0; for (int i = 0; i < (int)a.size(); i++) { sum += a[i]; for(int j = sum; j >= 0; j--) { if (j - a[i] >= 0) { dp[j] += dp[j - a[i]]; } } } int maxFrequency = -1; int mostFrequentSum = -1; for (int i = 0; i <= sum; i++) { if (dp[i] >= maxFrequency) { maxFrequency = dp[i]; mostFrequentSum = i; } } return mostFrequentSum; } 来降低空间复杂度。 / p>

Demo

注意:在您的示例中,最常见的总和是6、8、10、12、14。请注意,仅选择1个元素,即。 6、8也可以。