给出长度 n 的数组。找到子数组元素的乘积之和。
解释
数组 A = [2,3,4] 长 3 。
长度 2 = [2,3],[3,4],[2,4]
的子阵列[2,3] = 6
中的元素产品[3,4] = 12
中的元素产品[2,4] = 8
中的元素产品长度 2 = 6 + 12 + 8 = 26
的子阵列总和同样,对于长度 3 ,Sum = 24
因为,对于更长的子阵列,产品可能更大,以模 1000000007 计算。
为所有可能长度的子阵列找到这些总和的有效方法是什么,即1,2,3,......,n其中 n 是数组的长度。
答案 0 :(得分:6)
有一个相当简单的方法:
构建术语(1 + A[i] * x)
的产品:
P = (1 + A[0] * x) * (1 + A[1] * x) * (1 + A[2] * x)...*(1 + A[n-1] * x)
如果我们打开括号,那么我们将得到多项式
P = 1 + B[1] * x + B[2] * x^2 + ... + B[n] * x^n
Kth系数B [k]等于长度为K的集合的乘积之和 - 例如B[n] = A[0]*A[1]*A[2]*..A[n-1], B[2] = A[0]*A[1] + A[0]*A[2] + ... + A[n-2]*A[n-1]
等等。
因此,为了找到所有可能集合的乘积之和,我们必须找到x = 1的多项式P的值,然后减去1以去除前导的第0项。如果我们不想考虑单元素集,则减去B1 = A [i]之和。
示例:
(1+2)(1+3)(1+4) = 60
60 - 1 = 59
59 - (2 + 3 + 4) = 50 = 24 + 26 - as your example shows
答案 1 :(得分:3)
我们首先创建一个递归关系。设f(n, k)
为长度为k
的长度为a
的长度为n
的子数组的所有乘积。基本案例很简单:
f(0, k) = 0 for all k
f(n, 0) = 1 for all n
第二条规则似乎有点违反直觉,但1是乘法的零元素。
现在我们找到了f(n+1, k)
的递归关系。我们想要所有大小为k
的子数组的乘积。这里有两种类型的子阵列:包含a[n+1]
的子阵列和不包含a[n+1]
的子阵列。不包括a[n+1]
的那些的总和恰好是f(n, k)
。包含a[n+1]
的内容恰好是所有添加了k-1
的长度为a[n+1]
的子数组,因此它们的总和乘积为a[n+1] * f(n, k-1)
。
这完成了我们的递归关系:
f(n, k) = 0 if n = 0
= 1 if k = 0
= f(n-1, k) + a[n] * f(n-1, k-1) otherwise
你可以使用一个巧妙的技巧来为动态编程使用非常有限的内存,因为函数f
仅依赖于两个早期的值:
int[] compute(int[] a) {
int N = a.length;
int[] f = int[N];
f[0] = 1;
for (int n = 1; n < N; n++) {
for (int k = n; k >= 1; k--) {
f[k] = (f[k] + a[n] * f[k-1]) % 1000000007;
}
}
return f;
}