簡體   English   中英

如何在時間和內存方面高效地生成集合元素組合的總和?

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

我有一個整數的隨機集合S ,並且該集合的基數( n )可能在10到1000之間變化。我需要存儲從該集合生成的大小為rnCr組合的所有和。 通常r的范圍是3到10。

例如,如果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,....等等。

我在Java中實現了findCombi函數(如下),該函數根據r大小的索引集為我提供了所有nCr組合,然后在另一個函數中篩選這些集以生成相應元素的總和。 但是程序給出堆空間錯誤,可能是由於指數性質,我有100-5000個這樣的集合S。 還是可能存在內存泄漏?

有沒有更快,更少內存消耗的方法呢?

注意: 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;            
}

我之前需要類似的東西,所以這里有一些代碼是從我當時所做的項目改編而來的。 allSums方法構建大小為r的索引列表,該列表用於表示所有可能的組合。 在每個步驟中,將當前總和添加到結果集中,然后生成下一個組合。 由於結果放在一組中,因此結果不可能出現兩次。 我提供了一種主要方法,因此您可以看到它的工作原理。 我希望這很清楚,隨時提出問題。

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