我正在尝试在整数列表中找到最常见的总和。
例如,在给定列表2 + 8 = 4 + 6 = 10
2 + 4 + 6 = 4 + 8 = 12
2 + 4 + 8 = 6 + 8 = 14
的情况下,最常见的总和为10、12和14,因为它们的总和有两种:
GridView
当然,其他可能的总和仅发生一次。我知道像这样的简单列表可以被强行使用,但是我想要某种一般性提示,以了解如何解决较大列表的问题。例如,也许我可以以某种方式利用动态编程?
答案 0 :(得分:2)
这是subset sum problem的变体。可以使用动态编程在时间复杂度为 O(n * sum)的伪多项式时间内完成。
dp(sum,i)= dp(sum-a [i],i-1)的总和
想象一下,您有一个解决方案,可以解决从0
到i-1
的所有元素的子集进行任何求和的可能性。对于dp(sum, i - 1)
的所有值,我们用sum
表示。为了在构成a[i]
的有效子集中包含新元素sum
,必须在sum - a[i]
的元素子集中为0
提供至少一个解决方案到i - 1
。然后,获得元素sum
至0
的元素子集的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>
注意:在您的示例中,最常见的总和是6、8、10、12、14。请注意,仅选择1个元素,即。 6、8也可以。