views:

274

answers:

5

I'm sorry for deleting the original question, here it is: We have a bag or an array of n integers, we need to find the product of each of the (n-1) subsets. e.g: S = {1, 0, 3, 6} ps[1] = 0*3*6 = 0; ps[2] = 1*3*6 = 18; etc. After discussions, we need to take care of the three cases and they are illustrated in the following:

1. S is a set (contains one zero element)
  for i=1 to n
    if s[i]=0
      sp[i] = s[1] * s[2] * ...* s[i-1] * s[i+1] *.....*s[n]
    else
      sp[i] = 0;

2. S is a bag (contains more than one zero element) 
  for i=1 to n
      sp[i] = 0;

3. S is a set (contains no zero elements)
   product = 1
   for i=1 to n
     product *= s[i];
   for i=1 to n
     sp[i] = product / s[i];

Thanks.

+2  A: 
Set product = 1;
for item in set:
   if item index == argument index
      ignore
   else
      product *= item

If I understand your question, this is the trivial solution. It should be easy to implement in any programming language.

Stefan Kendall
You understood me, and your algorithm is completely correct, but the problem is that to compute it for all subsets, the complexity will be of O(n^2), we're looking for an optimum solution.
guirgis
Ah. You didn't ask for an optimal solution :)
Stefan Kendall
That's right, Sorry for missing that :)
guirgis
+12  A: 

If the set is very large, it may be convenient to:

  • compute the product P of all the elements beforehand, and then
  • for each element x, obtain a (n-1) product as P/x

If the set contains zero (i.e. P=0, x=0), you must deal with it as a special case.

EDIT. Here is a solution in Scheme, taking into account andand's answer. I'm a complete beginner - can someone help me improve the following code (make it more efficient, more readable, more lisp-ish)? (Feel free to edit my answer.)

#!/usr/bin/env guile !#
(use-modules (ice-9 pretty-print))

(define (count-zeros l)
    (cond ((null? l) 0)
          ((= 0 (car l)) (+ 1 (count-zeros (cdr l))))
          (else (count-zeros (cdr l)))))

(define (non-zero-product l)
    (define (non-zero-product-loop l product)
        (cond ((null? l) product)
              ((= 0 (car l)) (non-zero-product-loop (cdr l) product))
              (else (non-zero-product-loop (cdr l) (* (car l) product)))))
    (non-zero-product-loop l 1))

(define (n-1-products l)
    (let ((nzeros (count-zeros l)))
         (cond ((> nzeros 1)
                   (map (lambda (x) 0) l))
               ((= 1 nzeros)
                   (map (lambda (x) (if (= 0 x) (non-zero-product l) 0)) l))
               (else 
                   (map (lambda (x) (/ (non-zero-product l) x)) l)))))

(pretty-print (n-1-products '(1 2 3 4 5)))
(pretty-print (n-1-products '(0 1 2 3 4)))
(pretty-print (n-1-products '(0 1 2 3 0)))
Federico Ramponi
I know your idea, my problem is that special case (zero elements), what will i do then, do i consider a different problem? But what happens when the set contains many zero elements? i think we need a generic solution that apply to all values.
guirgis
@guirgis - A set is a collection of distinct elements. It can only have one instance of any particular element. If it can contain more than one instance of a particular element, it is a multiset (or bag). If you have a bag with more than one zero, the result is trivial -- think about it.
tvanfosson
I think @Federico's solution is generic and applies to all the values encompassed by the example in your question. Bear in mind that if you have a set of integers then 0 can only be a member of the set once; a set cannot contain many 0 elements.
High Performance Mark
@guirgis - the most obvious way to handle a set with a zero is simply to mark all of the other results as zero when you encounter one and continue building the product without that element -- i.e., devolve to the special case of calculating just the one subset product for the subset omitting the single zero value.
tvanfosson
Firstly, i'm sorry for misusing the word "Set", i should have used a "bag" or "array".Secondly, Thanks for your ideas, i'm trying to understand it.
guirgis
Oh, If the bag contains more than one zero, then all the subsets products will be "Zeros".And if it contains one zero then all the subsets except the one of the zero element will be zeros and the one of the zero element will be the product of the rest of the elements.Thank you tvanfosson and all the guys for your hints although it made me feel kinda stupid.
guirgis
A: 

Assuming you can use Python:

You can use the combinations method from the itertools module to lazily generate the various subsets of the set in question. Once you have that, you can use reduce and operator.mul to generate the product of each one.

Hank Gay
Thanks Hank, a pretty implementation, but i think i kinda need the algorithm not the implementation.
guirgis
+10  A: 

You need to explicitly consider the three cases:

1) No zeros: Precompute the product of all of the elements and divide out the desired set element from that product.

2) One zero: Precompute the product of the non-zero elements. The answer is always 0 except when you remove the single zero element, in which case it's the precomputed product.

3) More than one zero: The answer is always 0.

This assumes that you have a data type that can contain the products... that is, you need to be careful that your product doesn't exceed the maximum value of the type you're using to store it.

For the actual implementation, always precompute the product of the non-zero elements and keep track of how many zeros there are. If the "set" is dynamic (its values change) you'll need to update the product and the zero count. When asked for a particular subset product, consider the various cases and act accordingly.

andand
Much more readable than the code version and very well detailed.
Matthieu M.
+1  A: 

You can solve this in O(N), using O(1) additional space (not counting the O(N) output array), without even using division. Here's the algorithm in Java.

static int[] products(int... nums) {
    final int N = nums.length;
    int[] prods = new int[N];
    int pi = 1;
    for (int i = 0; i < N; i++) {
        prods[i] = pi;
        pi *= nums[i];
    }
    int pj = 1;
    for (int j = N-1; j >= 0; j--) {
        prods[j] *= pj;
        pj *= nums[j];
    }
    return prods;
}

//...
System.out.println(
   Arrays.toString(products(1, 2, 3, 4, 5))
); // prints "[120, 60, 40, 30, 24]"

See also

polygenelubricants