简体   繁体   中英

How to generate sums of combinations of elements of a set efficiently in terms of time and memory?

I have a random set S of integers and the cardinality ( n ) of this set may vary from 10 to 1000. I need to store all sums of the nCr combinations of size r generated from this set. Usually r range from 3 to 10.

Eg if S ={102,233,344,442,544,613,71289,836,97657,12} and r =4, Then The sums generated will be {0,1,2,3}=102+233+344+442, {0,1,2,4}=102+233+344+544,....so on.

I implemented a findCombi function (below) in Java which gave me all nCr combinations in terms of r sized sets of indices and then I sifted through these sets in another function to generate the sum of corresponding elements. But the program is giving heapspace error, probably because of exponential nature and I have 100-5000 of such sets, S . Or may be there is a memory leak?

Is there a faster and lesser-memory consuming way to do it?

Note: dsize = n , combiSize = r

List <List<Integer>> findCombi(int dsize,int combiSize) {
     if( (combiSize==0) ||  (dsize==0) ){
        return null;
    }

    long n=dsize;
    int r=combiSize;
    for(int i=1;i<combiSize;i++) {
       n=n*(dsize-i);           
       r=r*i;
    }
    int totalcombi=(int) n/r;        
    List <List<Integer>> combiData=new ArrayList<>(totalcombi);

    int pos;        
    List <Integer> combi=new ArrayList<>(combiSize);        
    for(int i=0;i<combiSize;i++) {
     combi.add(i,i);           
    }

    combiData.add(new ArrayList<>(combi));         
    pos=combiSize-1;
    while(true) {
        if(combi.get(pos)<(dsize-combiSize+pos)) {
            combi.set(pos,combi.get(pos)+1);              
            if(pos==(combiSize-1)) {
                combiData.add(new ArrayList<>(combi));                   
            }                  
            else {
                combi.set(pos+1,combi.get(pos));
                pos++;
            }   
        }
        else {
            pos--;
        }
        if(pos==-1) {
            break;
        }
    } 
  return combiData;            
}

I needed something like that earlier, so here is some code adapted from the project I made back then. The method allSums builds a list of indices of size r, which is used to represent all the possible combinations. At each step, the current sum is added to the result set, then the next combination is generated. Since the results are put in a set, there is no way a result could appear twice. I included a main method so you can see it work. I hope this is clear, feel free to ask questions.

import java.util.*;


public class Program {


static private Set<Integer> allSums(List<Integer> values, int r) {      
    HashSet<Integer> res = new HashSet<>();

    if ((values.isEmpty()) || r > values.size()) {
        return res;
    }

    // build the list of indices
    List<Integer> li = new ArrayList<>();
    for (int i = 0; i < r; i++) {
        li.add(i);
    }
    li.add(values.size());  // artificial last index : number of elements in set

    while (true) {
        // add the current sum to the result
        int sum = 0;
        for (int i = 0; i < r; i++) {
            sum += values.get(li.get(i));
        }
        res.add(sum);

        // move to the next combination
        // first, find the last index that can be incremented
        int i = r-1;
        while ((i >= 0) && (li.get(i) == li.get(i+1)-1)) {
            i--;
        }
        // was such an index found ?
        if (i == -1) {
            break;  // if not, it's over
        }
        // increment the last index and set all the next indices to their initial value
        li.set(i,li.get(i)+1);
        for (int j = i+1; j < r; j++) {
            li.set(j, li.get(j-1)+1);
        }
    }

    return res;
}

public static void main(String[] args) {
    List<Integer> values = new ArrayList<>();
    values.add(10);
    values.add(100);
    values.add(1000);
    values.add(10000);
    values.add(100000);

    Set<Integer> s = allSums(values, 3);

    for (int i : s) {
        System.out.println(i);
    }       
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM