Obtaining a powerset of a set in Java

后端 未结 26 1701
青春惊慌失措
青春惊慌失措 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:56

    The following solution is borrowed from my book "Coding Interviews: Questions, Analysis & Solutions":

    Some integers in an array are selected that compose a combination. A set of bits is utilized, where each bit stands for an integer in the array. If the i-th character is selected for a combination, the i-th bit is 1; otherwise, it is 0. For instance, three bits are used for combinations of the array [1, 2, 3]. If the first two integers 1 and 2 are selected to compose a combination [1, 2], the corresponding bits are {1, 1, 0}. Similarly, bits corresponding to another combination [1, 3] are {1, 0, 1}. We are able to get all combinations of an array with length n if we can get all possible combinations of n bits.

    A number is composed of a set of bits. All possible combinations of n bits correspond to numbers from 1 to 2^n-1. Therefore, each number in the range between 1 and 2^n-1 corresponds to a combination of an array with length n. For example, the number 6 is composed of bits {1, 1, 0}, so the first and second characters are selected in the array [1, 2, 3] to generate the combination [1, 2]. Similarly, the number 5 with bits {1, 0, 1} corresponds to the combination [1, 3].

    The Java code to implement this solution looks like below:

    public static ArrayList<ArrayList<Integer>> powerSet(int[] numbers) {
        ArrayList<ArrayList<Integer>> combinations = new ArrayList<ArrayList<Integer>>(); 
        BitSet bits = new BitSet(numbers.length);
        do{
            combinations.add(getCombination(numbers, bits));
        }while(increment(bits, numbers.length));
    
        return combinations;
    }
    
    private static boolean increment(BitSet bits, int length) {
        int index = length - 1;
    
        while(index >= 0 && bits.get(index)) {
            bits.clear(index);
            --index;
        }
    
        if(index < 0)
            return false;
    
        bits.set(index);
        return true;
    }
    
    private static ArrayList<Integer> getCombination(int[] numbers, BitSet bits){
        ArrayList<Integer> combination = new ArrayList<Integer>();
        for(int i = 0; i < numbers.length; ++i) {
            if(bits.get(i))
                combination.add(numbers[i]);
        }
    
        return combination;
    }
    

    The method increment increases a number represented in a set of bits. The algorithm clears 1 bits from the rightmost bit until a 0 bit is found. It then sets the rightmost 0 bit to 1. For example, in order to increase the number 5 with bits {1, 0, 1}, it clears 1 bits from the right side and sets the rightmost 0 bit to 1. The bits become {1, 1, 0} for the number 6, which is the result of increasing 5 by 1.

    0 讨论(0)
  • 2020-11-22 11:56

    This is my recursive solution which can get the power set of any set using Java Generics. Its main idea is to combine the head of the input array with all the possible solutions of the rest of the array as follows.

    import java.util.LinkedHashSet;
    import java.util.Set;
    
    public class SetUtil {
        private static<T>  Set<Set<T>> combine(T head, Set<Set<T>> set) {
            Set<Set<T>> all = new LinkedHashSet<>();
    
            for (Set<T> currentSet : set) {
                Set<T> outputSet = new LinkedHashSet<>();
    
                outputSet.add(head);
                outputSet.addAll(currentSet);
    
                all.add(outputSet);
            }
    
            all.addAll(set);        
    
            return all;
        }
    
        //Assuming that T[] is an array with no repeated elements ...
        public static<T> Set<Set<T>> powerSet(T[] input) {
            if (input.length == 0) {
                Set <Set<T>>emptySet = new LinkedHashSet<>();
    
                emptySet.add(new LinkedHashSet<T>());
    
                return emptySet;
            }
    
            T head = input[0];
            T[] newInputSet = (T[]) new Object[input.length - 1];
    
            for (int i = 1; i < input.length; ++i) {
                newInputSet[i - 1] = input[i];
            }
    
            Set<Set<T>> all = combine(head, powerSet(newInputSet));
    
            return all;
        }
    
        public static void main(String[] args) {            
            Set<Set<Integer>> set = SetUtil.powerSet(new Integer[] {1, 2, 3, 4, 5, 6});
    
            System.out.println(set);
        }
    }
    

    This will output:

    [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 4], [1, 2, 3, 5, 6], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 3], [1, 2, 4, 5, 6], [1, 2, 4, 5], [1, 2, 4, 6], [1, 2, 4], [1, 2, 5, 6], [1, 2, 5], [1, 2, 6], [1, 2], [1, 3, 4, 5, 6], [1, 3, 4, 5], [1, 3, 4, 6], [1, 3, 4], [1, 3, 5, 6], [1, 3, 5], [1, 3, 6], [1, 3], [1, 4, 5, 6], [1, 4, 5], [1, 4, 6], [1, 4], [1, 5, 6], [1, 5], [1, 6], [1], [2, 3, 4, 5, 6], [2, 3, 4, 5], [2, 3, 4, 6], [2, 3, 4], [2, 3, 5, 6], [2, 3, 5], [2, 3, 6], [2, 3], [2, 4, 5, 6], [2, 4, 5], [2, 4, 6], [2, 4], [2, 5, 6], [2, 5], [2, 6], [2], [3, 4, 5, 6], [3, 4, 5], [3, 4, 6], [3, 4], [3, 5, 6], [3, 5], [3, 6], [3], [4, 5, 6], [4, 5], [4, 6], [4], [5, 6], [5], [6], []]
    
    0 讨论(0)
  • 2020-11-22 11:59

    Here is to generate a power set. The idea is first = S[0] and smaller sets be S[1,...n].

    Compute all subsets of smallerSet and put them in allsubsets.

    For each subsets in allsubsets, clone it and add first to the subset.

    ArrayList<ArrayList<Integer>> getSubsets(ArrayList<Integer> set, int index){
        ArrayList<ArrayList<Integer>> allsubsets;
        if(set.size() == index){
            allsubsets = new ArrayList<ArrayList<Integer>>();
            allsubsets.add(new ArrayList<Integer>()); // the empty set 
        }else{
            allsubsets = getSubsets(set, index+1);
            int item = set.get(index);
    
            ArrayList<ArrayList<Integer>> moresubsets = new ArrayList<ArrayList<Integer>>();
    
            for(ArrayList<Integer> subset: allsubsets){
                ArrayList<Integer> newsubset = new ArrayList<Integer>();
    
                newsubset.addAll(subset);
                newsubset.add(item);
                moresubsets.add(newsubset);
    
            }
    
            moresubsets.addAll(moresubsets);
    
        }
    
        return allsubsets;
    }
    
    0 讨论(0)
  • 2020-11-22 12:00

    If you're using Eclipse Collections (formerly GS Collections), you can use the powerSet() method on all SetIterables.

    MutableSet<Integer> set = UnifiedSet.newSetWith(1, 2, 3);
    System.out.println("powerSet = " + set.powerSet());
    // prints: powerSet = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
    

    Note: I am a committer for Eclipse Collections.

    0 讨论(0)
  • 2020-11-22 12:00

    Here is an easy iterative O(2^n) solution:

    public static Set<Set<Integer>> powerSet(List<Integer> intList){
    
        Set<Set<Integer>> result = new HashSet();
        result.add(new HashSet());
    
        for (Integer i : intList){
    
            Set<Set<Integer>> temp = new HashSet();
    
            for(Set<Integer> intSet : result){
    
                intSet = new HashSet(intSet);
                intSet.add(i);                
                temp.add(intSet);
            }
            result.addAll(temp);
        }
        return result;
    }
    
    0 讨论(0)
  • 2020-11-22 12:01
    import java.util.Set;
    import com.google.common.collect.*;
    
    Set<Set<Integer>> sets = Sets.powerSet(ImmutableSet.of(1, 2, 3));
    
    0 讨论(0)
提交回复
热议问题