Efficient algorithm to calculate the sum of all k-products

前端 未结 6 1935
青春惊慌失措
青春惊慌失措 2021-02-06 04:49

Suppose you are given a list L of n numbers and an integer k. Is there an efficient way to calculate the sum of all products of

相关标签:
6条回答
  • 2021-02-06 05:29

    An interesting property you could explore is the distributive property of multiplication in relation to addition.

    L=[a,b,c,d]
    

    When k = 1, it's trivial:

    S=a+b+c+d
    

    When k = 2:

    S = a * (b + c + d) + b * (c + d) + c * d
    

    When k = 3, things get a bit more interesting:

    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
    

    And for k = 4:

    S = a * b * c * d
    

    This should hold for larger values of n.

    An implementation in 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;
     }
    

    Which can be further improved by memoization.

    0 讨论(0)
  • 2021-02-06 05:31

    Let F(X,k,n) be the k-product sum of first n elements of array X.

    F(X,k,n) = F(X,k,n-1)+F(X,k-1,n-1)*X[n]

    which you can solve using dynamic programming. Complexity = O(kn).

    End conditions for F(X,k,n): When n=k F(X,k,k) = X[1]* X[2]*...*X[n]

    More details:

    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
    
    0 讨论(0)
  • 2021-02-06 05:31

    For k=2,

    let's s = SUM_x_in_L x (sum of the numbers) and sq = SUM_x_in_L x^2 (sum of the squares)

    then it's SUM_x_in_L (s - x) * x / 2 = (s * s - sq) / 2

    0 讨论(0)
  • 2021-02-06 05:36

    Algebraically, for k=2 just take the sum of the elements of L, square it, and subtract the sum of the squares of L. That is:

    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;
    

    In your example, what you are computing is this

    (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
    

    This should give you a hint for how to proceed in general.

    0 讨论(0)
  • 2021-02-06 05:40

    You can reduce k by 1:

    e.g. for k=2

    1*3 + 1*4 + 1*6 + 3*4 + 3*6 + 4*6
    

    ==

    1*(3+4+6)+3*(4+6)+4*6
    

    and for k=3

    1*3*4 + 1*3*6 + 3*4*6
    

    ==

    1*3*(4+6) + 3*4*6
    

    So basically you cycle your list, then recurse to the same algorithm with k reduced by 1 and only the rest of the list

    0 讨论(0)
  • 2021-02-06 05:47

    Yes, there is a way. Consider the polynomial

    (X + a[0]) * (X + a[1]) * ... * (X + a[n-1])
    

    Its coefficients are just the sums of the k-products, its degree is n, so you can calculate the sum of all k-products for all k simultaneously in O(n^2) steps.

    After s steps, the coefficient of Xs-k is the sum of the k-products of the first s array elements. The k-products of the first s+1 elements fall into two classes, those involving the (s+1)st element - these have the form a[s]*((k-1)-product of the first s elements) - and those not involving it - these are the k-products of the first s elements.

    Code such that result[i] is the coefficient of Xi (the sum of the (n-i)-products):

    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;
    }
    

    If you only want the sum of the k-products for one k, you can stop the calculation at index n-k, giving an O(n*(n-k)) algorithm - that's good if k >= n/2. To get an O(n*k) algorithm for k <= n/2, you have to organise the coefficient array the other way round, so that result[k] is the coefficient of Xn-k (and stop the calculation at index k if you want only one sum):

    int *k_products_2(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] = 1;
            for(i = 1; i <= d; ++i){
                new[i] = old[i] + a[d-1]*old[i-1];
            }
            free(old);
            old = new;
        }
        return old;
    }
    
    0 讨论(0)
提交回复
热议问题