简体   繁体   English

如何在时间和内存方面高效地生成集合元素组合的总和?

[英]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. 我有一个整数的随机集合S ,并且该集合的基数( n )可能在10到1000之间变化。我需要存储从该集合生成的大小为rnCr组合的所有和。 Usually r range from 3 to 10. 通常r的范围是3到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. 例如,如果S = {102,233,344,442,544,613,71289,836,97657,12}且r = 4,则生成的总和将为{0,1,2,3} = 102 + 233 + 344 + 442,{0,1,2 ,4} = 102 + 233 + 344 + 544,....等等。

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. 我在Java中实现了findCombi函数(如下),该函数根据r大小的索引集为我提供了所有nCr组合,然后在另一个函数中筛选这些集以生成相应元素的总和。 But the program is giving heapspace error, probably because of exponential nature and I have 100-5000 of such sets, S . 但是程序给出堆空间错误,可能是由于指数性质,我有100-5000个这样的集合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 注意: dsize = ncombiSize = 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. allSums方法构建大小为r的索引列表,该列表用于表示所有可能的组合。 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);
    }       
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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