假设您获得了L
个n
个数字和k<n
整数的列表。有没有一种有效的方法来计算k
中L
个不同数字的所有产品的总和?
例如,请L=[1,3,4,6]
和k=2
。然后我要找的号码是
1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6
。
你能想到一种避免生成大小k
的所有子集的方法吗?
答案 0 :(得分:7)
设F(X,k,n)为数组X的前n个元素的k乘积和。
F(X,k,n)= F(X,k,n-1)+ F(X,k-1,n-1)* X [n]
您可以使用动态编程解决。复杂度= O(kn)。
F(X,k,n)的结束条件:当n = k F(X,k,k)= X [1] * X [2] * ... * X [n]
更多详情:
F(X,1,1) = X[1]
F(X,1,i) = F(X,1,i-1)+X[i] for i=2...n
For j=2..n:
For i = 1..k:
if i<j:
F(X,i,j) = F(X,i,j-1)+F(X,i-1,j-1)*X[j]
else if i==j:
F(X,i,j) = F(X,i-1,j-1)*X[j]
else:
pass
答案 1 :(得分:3)
是的,有办法。考虑多项式
(X + a[0]) * (X + a[1]) * ... * (X + a[n-1])
其系数只是k
- 产品的总和,其度数为n
,因此您可以为所有k
计算所有k
- 产品的总和同时进行O(n ^ 2)步骤。
在s
步之后,X s-k 的系数是第一个k
数组元素的s
- 乘积之和。第一个k
元素的s+1
- 产品分为两类,即(s+1)
st 元素 - 这些类型的格式为a[s]*((k-1)
- 第一个s
元素的产品 - 以及那些不涉及它们的产品 - 这些是k
- 第一个s
元素的产品。
代码使得result[i]
是X i 的系数((n-i)
- 产品的总和):
int *k_products_1(int *a, int n){
int *new, *old = calloc((n+1)*sizeof(int));
int d, i;
old[0] = 1;
for(d = 1; d <= n; ++d){
new = calloc((n+1)*sizeof(int));
new[0] = a[d-1]*old[0];
for(i = 1; i <= d; ++i){
new[i] = old[i-1] + a[d-1]*old[i];
}
free(old);
old = new;
}
return old;
}
如果您只想要一个k
的{{1}} - 产品的总和,则可以在索引k
停止计算,给出O(n *(nk))算法 - 如果n-k
那就好了。要获得k >= n/2
的O(n * k)算法,必须反过来组织系数数组,以便k <= n/2
是X nk 的系数(如果只需要一个总和,则在索引result[k]
停止计算:
k
答案 2 :(得分:0)
你可以将k减少1:
e.g。对于k = 2
1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6
==
1*(3+4+6)+3*(4+6)+4*6
并且对于k = 3
1*3*4 + 1*3*6 + 3*4*6
==
1*3*(4+6) + 3*4*6
所以基本上你循环你的列表,然后递归到相同的算法,k减少1,只剩下列表的其余部分
答案 3 :(得分:0)
对于k = 2,
让我们s = SUM_x_in_L x
(数字之和)和sq = SUM_x_in_L x^2
(正方形之和)
然后它是SUM_x_in_L (s - x) * x / 2 = (s * s - sq) / 2
答案 4 :(得分:0)
您可以探索的一个有趣的属性是乘法与加法相关的分配属性。
L=[a,b,c,d]
当k = 1时,它是微不足道的:
S=a+b+c+d
当k = 2时:
S = a * (b + c + d) + b * (c + d) + c * d
当k = 3时,事情会变得更有趣:
S = a * b * ( c + d) + (c * d) * (a + b)
S = a * (b * (c + d)) + c * d) + b * (c * d) <-- this form lends itself better to the algorithm
对于k = 4:
S = a * b * c * d
这应该适用于较大的n值。
C#中的实现:
private static int ComputeSum(int[] array, int offset, int K)
{
int S = 0;
if (K == 1)
{
for (int i = offset; i < array.Length; i++)
S += array[i];
}
else if ((array.Length - offset) == K)
{
S = array[offset] * ComputeSum(array, offset + 1, K - 1);
}
else if (offset < array.Length)
{
S = ComputeSum(array, offset + 1, K) + array[offset] * ComputeSum(array, offset + 1, K - 1);
}
return S;
}
通过记忆可以进一步改进。
答案 5 :(得分:0)
代数地,对于k=2
,只需取L
的元素之和,将其平方,然后减去L
的平方和。那就是:
int sum = 0;
int sqSum = 0;
for (int i=0; i<n; ++i) {
sum += L[i];
sqSum += L[i]*L[i];
}
return sum*sum - sqSum;
在您的示例中,您正在计算的是
(1 + 3 + 4 + 6)^2 - (1^2 + 3^2 + 4^2 + 6^2) = 1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6
这应该会为您提供一般性的提示。