假设我有一个数组{1, 2, 5, 4}
和m = 3
。
我需要找到:
1*2*5 + 1*2*4 + 1*5*4 + 2*5*4
即m元素的所有组合与n个元素的数组相乘的总和。
可能的解决方案之一是找到所有组合,然后解决它,但这将是O(nCm)
解决方案。有没有更好的算法?
答案 0 :(得分:5)
这个问题相当于计算给定根(Vieta's theorem)的多项式的Mth系数。 Delphi中的自适应算法(O(N)存储器和O(N ^ 2)时间):
function CalcMultiComb(const A: array of Integer; const M: Integer): Integer;
var
i, k, N: Integer;
Coeff: TArray<Integer>;
begin
N := Length(A);
if (N = 0) or (M > N) then
Exit;
SetLength(Coeff, N + 1);
Coeff[0] := -A[0];
Coeff[1] := 1;
for k := 2 to N do begin
Coeff[k] := 1;
for i := k - 2 downto 0 do
Coeff[i + 1] := Coeff[i] - A[k-1] * Coeff[i + 1];
Coeff[0] := -A[k-1] * Coeff[0];
end;
Result := Coeff[N - M];
if Odd(N - M) then
Result := - Result;
end;
调用CalcMultiComb([1,2,3,4],M),M = 1..4给出结果10,35,50,24
答案 1 :(得分:4)
我脑子里有一个动态编程解决方案,只是想分享。时间复杂度为O(k * n ^ 2),n为总数。
我们的想法是,我们开始填写从0到k -1的每个位置。因此,如果我们假设位置ith
,则此位置的填充数量为a
,因此以a
开头的所有组合的总和将是a
的总和(i + 1)th
倍从(a + 1)
data
的所有组合
注意:我已经更新了解决方案,因此可以使用任何数组public int cal(int n, int k , int[]data){
int [][] dp = new int[k][n + 1];
for(int i = 1; i <= n; i++){
dp[k - 1][i] = data[i - 1];
}
for(int i = k - 2; i >= 0; i--){
for(int j = 1 ; j <= n; j++){
for(int m = j + 1 ; m <= n; m++){
dp[i][j] += data[j - 1]*dp[i + 1][m];
}
}
}
int total = 0;
for(int i = 1; i <= n; i++){
total += dp[0][i];
}
return total;
}
,我的语言是Java,所以您可以注意到数组的索引是基于0的,从0开始到n-1
{{1}}
答案 2 :(得分:2)
我想出了同样的问题。我也通过Vieta算法找到了解决方案。我调整算法而不是计算不需要的多项式系数。复杂度为O(N * M)。我查看了DFT和FFT,但如果M足够小,这种方法甚至比快速傅里叶变换算法更快。这是java btw。
public BigInteger sumOfCombMult(Integer[] roots, int M)
{
if (roots.length < M)
{
throw new IllegalArgumentException("size of roots cannot be smaller than M");
}
BigInteger[] R = new BigInteger[roots.length];
for (int i = 0; i < roots.length; i++)
{
R[i] = BigInteger.valueOf(roots[i]);
}
BigInteger[] coeffs = new BigInteger[roots.length + 1];
coeffs[0] = BigInteger.valueOf(roots[0]);
int lb = 0;
for (int i = 1; i < roots.length; i++)
{
lb = Math.max(i - M, 0);
coeffs[i] = R[i].add(coeffs[i - 1]);
for (int j = i - 1; j > lb; j--)
{
coeffs[j] = R[i].multiply(coeffs[j]).add(coeffs[j - 1]);
}
if (lb == 0)
{
coeffs[0] = coeffs[0].multiply(R[i]);
}
}
return coeffs[roots.length - M];
}