Obtaining a powerset of a set in Java

后端 未结 26 1704
青春惊慌失措
青春惊慌失措 2020-11-22 11:33

The powerset of {1, 2, 3} is:

{{}, {2}, {3}, {2, 3}, {1, 2}, {1, 3}, {1, 2, 3}, {1}}

Let\'s say I have a Set in Java:<

26条回答
  •  长情又很酷
    2020-11-22 11:44

    Some of the solutions above suffer when the size of the set is large because they are creating a lot of object garbage to be collected and require copying data. How can we avoid that? We can take advantage of the fact that we know how big the result set size will be (2^n), preallocate an array that big, and just append to the end of it, never copying.

    The speedup grows quickly with n. I compared it to João Silva's solution above. On my machine (all measurements approximate), n=13 is 5x faster, n=14 is 7x, n=15 is 12x, n=16 is 25x, n=17 is 75x, n=18 is 140x. So that garbage creation/collection and copying is dominating in what otherwise seem to be similar big-O solutions.

    Preallocating the array at the beginning appears to be a win compared to letting it grow dynamically. With n=18, dynamic growing takes about twice as long overall.

    public static  List> powerSet(List originalSet) {
        // result size will be 2^n, where n=size(originalset)
        // good to initialize the array size to avoid dynamic growing
        int resultSize = (int) Math.pow(2, originalSet.size());
        // resultPowerSet is what we will return
        List> resultPowerSet = new ArrayList>(resultSize);
    
        // Initialize result with the empty set, which powersets contain by definition
        resultPowerSet.add(new ArrayList(0)); 
    
        // for every item in the original list
        for (T itemFromOriginalSet : originalSet) {
    
            // iterate through the existing powerset result
            // loop through subset and append to the resultPowerset as we go
            // must remember size at the beginning, before we append new elements
            int startingResultSize = resultPowerSet.size();
            for (int i=0; i oldSubset = resultPowerSet.get(i);
    
                // create a new element by adding a new item from the original list
                List newSubset = new ArrayList(oldSubset);
                newSubset.add(itemFromOriginalSet);
    
                // add this element to the result powerset (past startingResultSize)
                resultPowerSet.add(newSubset);
            }
        }
        return resultPowerSet;
    }
    

提交回复
热议问题