假设我们有一套
{a_1, a_2, a_3, ..., a_n}
目标是找到我们以下列方式创建的总和:我们找到长度为3的所有子集,然后将每个子集的元素相乘(对于子集{b_1, b_2, b_3}
,结果将为b_1*b_2*b_3
)。最后,我们总结了所有这些产品。
我正在寻找最短的时间执行算法。
实施例
SET: {3, 2, 1, 2}
Let S be our sum.
S = 3*2*1 + 3*2*2 + 2*1*2 + 3*1*2 = 28
答案 0 :(得分:5)
以下是O(n^2)
方法:
sum = SUM(list)
answer = 0
for each i from 0 to n:
sum -= list[i]
remains = sum
for each j from i+1 to n:
remains -= list[j]
answer += list[i] * list[j] * (remains)
这是有效的,因为对于每两个元素x,y
,您需要求和x*y*z
(对于所有元素z
),但所有可能z
值的总和为{{ 1}}。
所以,不是做SUM(list) - x - y
,而是基本做x*y*z1 + x*y*z2 + ... + x*y*z(n-2)
编辑:由于@AbhishekBansal所提及的“尾部”不会增加而编辑多次计数。您需要将每个元素仅与列表的“尾部”相乘,其中尾部是x*y*(z1 + ... + z(n-2))
中最后一个元素之后的所有元素。
答案 1 :(得分:2)
C ++中的完整工作代码(跟随Amit的想法)
#include <iostream>
using namespace std;
int main()
{
int s[] = {3, 2, 1, 2};
double sumOfFullList = 0;
for ( int i = 0; i < 4; i++ )
sumOfFullList += s[i];
double sum = 0;
for ( int i = 0; i < 4; i++ ) {
double sumOfList = sumOfFullList - s[i];
sumOfFullList -= s[i];
for ( int j = i+1; j < 4; j++ ) {
sumOfList -= s[j];
sum += s[i]*s[j]*(sumOfList);
//cout << s[i] << " " << s[j] << " " << sumOfList;
}
}
cout << sum << endl;
return 0;
}
输出:
28
答案 2 :(得分:1)
在允许重复时更容易计算乘法三元组的总和(如a_1 * a_1 * a_1)。这笔金额只是(sum^3)
。
由于不允许重复,我们可以减去它们:(sum^3 - 3*sumsquares*sum)
。
但是上面的公式减去主对角线上的元素3次,而应该只减去一次。需要补偿:(sum^3 - 3*sumsquares*sum + 2*sumcubes)
。
上面的公式没有考虑到3!每个三元组的排列。所以它应该除以3!
。
最后我们有一个线性时间算法:
result = (sum^3 - 3*sumsquares*sum + 2*sumcubes)/6