43

I want to find the subsets of a set of integers. It is the first step of "Sum of Subsets" algorithm with backtracking. I have written the following code, but it doesn't return the correct answer:

BTSum(0, nums);
///**************
ArrayList<Integer> list = new ArrayList<Integer>();

public static ArrayList<Integer> BTSum(int n, ArrayList<Integer> numbers) {
    if (n == numbers.size()) {
        for (Integer integer : list) {
            System.out.print(integer+", ");
        }
        System.out.println("********************");
        list.removeAll(list);
        System.out.println();
    } else {
        for (int i = n; i < numbers.size(); i++) {
            if (i == numbers.size() - 1) {
                list.add(numbers.get(i));
                BTSum(i + 1, numbers);
            } else {
                list.add(numbers.get(i));
                for (int j = i+1; j < numbers.size(); j++)
                BTSum(j, numbers);
            }
        }
    }

    return null;
}

For example, if I want to calculate the subsets of set = {1, 3, 5} The result of my method is:

 1, 3, 5, ********************

 5, ********************

 3, 5, ********************

 5, ********************

 3, 5, ********************

 5, ********************

I want it to produce:

1, 3, 5 
1, 5
3, 5
5

I think the problem is from the part list.removeAll(list); but I dont know how to correct it.

reformed
  • 4,505
  • 11
  • 62
  • 88
Elton.fd
  • 1,575
  • 3
  • 17
  • 24
  • 4
    :) http://www.cs.princeton.edu/introcs/23recursion/Combinations.java.html – Mihai Toader Jan 09 '11 at 15:44
  • 2
    Is it a homework? If it is, search SO, your classmates has already asked. Invest sometime in debugging. – Nishant Jan 09 '11 at 15:45
  • 9
    shoudnt the output contain also `1,3` and `1` and `3`? – phimuemue Jan 09 '11 at 15:52
  • possible duplicate of [How to find all possible subsets of a given array?](http://stackoverflow.com/questions/679203/how-to-find-all-possible-subsets-of-a-given-array) – moinudin Jan 09 '11 at 15:55
  • @marcdog, If the original question is about how to modify the backtracking algorithm, I'd keep it open vs that question you listed. If it is about any possible way, I'd vote to close. – Nick Larsen Jan 09 '11 at 15:58
  • http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/Sets.html#powerSet(java.util.Set) – avianey Aug 17 '16 at 13:19
  • [Guava](https://google.github.io/guava/releases/21.0/api/docs/com/google/common/collect/Sets.html#powerSet-java.util.Set-) can be used for powerset – firstpostcommenter Apr 14 '18 at 08:20

16 Answers16

89

What you want is called a Powerset. Here is a simple implementation of it:

public static Set<Set<Integer>> powerSet(Set<Integer> originalSet) {
        Set<Set<Integer>> sets = new HashSet<Set<Integer>>();
        if (originalSet.isEmpty()) {
            sets.add(new HashSet<Integer>());
            return sets;
        }
        List<Integer> list = new ArrayList<Integer>(originalSet);
        Integer head = list.get(0);
        Set<Integer> rest = new HashSet<Integer>(list.subList(1, list.size()));
        for (Set<Integer> set : powerSet(rest)) {
            Set<Integer> newSet = new HashSet<Integer>();
            newSet.add(head);
            newSet.addAll(set);
            sets.add(newSet);
            sets.add(set);
        }
        return sets;
    }

I will give you an example to explain how the algorithm works for the powerset of {1, 2, 3}:

  • Remove {1}, and execute powerset for {2, 3};
    • Remove {2}, and execute powerset for {3};
      • Remove {3}, and execute powerset for {};
        • Powerset of {} is {{}};
      • Powerset of {3} is 3 combined with {{}} = { {}, {3} };
    • Powerset of {2, 3} is {2} combined with { {}, {3} } = { {}, {3}, {2}, {2, 3} };
  • Powerset of {1, 2, 3} is {1} combined with { {}, {3}, {2}, {2, 3} } = { {}, {3}, {2}, {2, 3}, {1}, {3, 1}, {2, 1}, {2, 3, 1} }.
João Silva
  • 89,303
  • 29
  • 152
  • 158
  • Is this 2^n time complexity? – user3335040 Sep 02 '14 at 21:40
  • @user3335040, yes, it is, since you always need to generate 2^n sets. – João Silva Jan 13 '15 at 15:58
  • I cannot understand the logic of step Powerset of {2, 3} is {2} combined with { {}, {3} } = { {}, {3}, {2}, {2, 3} }; because in the previous step head has 3 and rest is empty. – Harish May 09 '17 at 22:01
  • @Harish the logic is the previous step PLUS everything in the previous + the new element. So you have `{{}, {3}}`, that stays in the new set, AND ALSO you add 2 to each of those and combine them together. So you would have `{} + 2 = {2}` and `{3} + 2 = {2,3}`. Combine with the previous and you have `{{} , {3}, {2}, {2,3}}` – cheenbabes May 28 '17 at 23:53
  • This is O(n^2) solution. Is it possible to get a solution with better time complexity? – Rizwan_Khan Mar 13 '20 at 16:01
24

Just a primer how you could solve the problem:

Approach 1

  • Take the first element of your number list
  • generate all subsets from the remaining number list (i.e. the number list without the chosen one) => Recursion!
  • for every subset found in the previous step, add the subset itself and the subset joined with the element chosen in step 1 to the output.

Of course, you have to check the base case, i.e. if your number list is empty.

Approach 2

It is a well known fact that a set with n elements has 2^n subsets. Thus, you can count in binary from 0 to 2^n and interpret the binary number as the corresponding subset. Note that this approach requires a binary number with a sufficient amount of digits to represent the whole set.

It should be a not too big problem to convert one of the two approaches into code.

phimuemue
  • 34,669
  • 9
  • 84
  • 115
15

Your code is really confusing and there is no explanation.

You can do iteratively with a bitmask that determines which numbers are in the set. Each number from 0 to 2^n gives a unique subset in its binary representation, for example

for n = 3:

i = 5 -> 101 in binary, choose first and last elements i = 7 -> 111 in binary, choose first 3 elements

Suppose there are n elements (n < 64, after all if n is larger than 64 you'll run that forever).

for(long i = 0; i < (1<<n); i++){
    ArrayList<Integer> subset = new ArrayList<Integer>();
    for(int j = 0; j < n; j++){
        if((i>>j) & 1) == 1){ // bit j is on
            subset.add(numbers.get(j));
        }
    }
    // print subset
}
Piva
  • 982
  • 6
  • 13
  • Could you elaborate on f((i>>j) & 1) == 1). I understand you are shifting i bits right, adding j zeros to i's binary representation. I also understand the bit wise & is comparing i >>j to 1 and seeing if all bits are on between i >> j and 1. But I just don't understand why this operation is the knowledgete that its time to add a subset – Brian Ogden Oct 26 '15 at 00:41
  • @BrianOgden `(i>>j)&1==1` is just testing if the j-th bit in `i` is set. The j-th bit in the number corresponds to whether the subset contains the j-th object. And i is looping for 0 to 2n-1. – Michael Anderson Oct 26 '15 at 01:57
  • Thanks @MichaelAnderson, that helps somewhat, but why does the j-th bit correspond to the subset containing the j-th object? – Brian Ogden Oct 26 '15 at 02:07
  • Not _the_ subset containing the `j`-th object - as there may be more than one. The `i`-th subset contains the `j`-th object if the `j`-th bit in `i` is set. I put a more complete explanation as an answer to your separate question (http://stackoverflow.com/questions/33337317/using-distinct-binary-numbers-to-find-subsets-of-a-given-set) – Michael Anderson Oct 26 '15 at 02:09
10

Considering a Noob Visitor (thanks to google) to this question - like me
Here is a recursive solution which works on simple principal :

Set = {a,b,c,d,e}
then we can break it to {a} + Subset of {b,c,d,e}

public class Powerset{
     String str = "abcd"; //our string
     public static void main(String []args){
        Powerset ps = new Powerset();
        for(int i = 0; i< ps.str.length();i++){ //traverse through all characters
            ps.subs("",i);
        }
     }

     void subs(String substr,int index)
     {
         String s = ""+str.charAt(index); //very important, create a variable on each stack
         s = substr+s; //append the subset so far
         System.out.println(s); //print

         for(int i=index+1;i<str.length();i++)
           subs(s,i); //call recursively

     }
}

OUTPUT

a
ab
abc
abcd
abd
ac
acd
ad
b
bc
bcd
bd
c
cd
d
NoobEditor
  • 15,563
  • 19
  • 81
  • 112
  • 4
    Simple and elegant solution to implement +1 – Luke Taylor Jan 06 '15 at 17:54
  • 1
    Love this solution - With out a doubt this is the way to go, Thanks for this , Noob if i understand correctly the way to think why this recursion works is : We start with a,b,c,d as the smallest subsets Then when we want to look at each bigger subset we say a->ab,ac,ad Then b->bc,bd (Not ab because we already had it) and so on, thats why advancing the index is the proper way. Thanks again – shimi_tap Feb 02 '16 at 20:29
  • yup....i code it under the logic that "ab" gets stored in recursion stack, then use that and append "c" to it...so "abc" is output on new recursion stack.print it and go on appending! :) – NoobEditor Feb 03 '16 at 03:41
4

It is clear that, the total number of subsets of any given set is equal to 2^(number of elements in the set). If set

A = {1, 2, 3}

then subset of A is:

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

If we look it is like binary numbers.

{ 000 }, { 001 }, { 010 }, { 011 }, { 100 }, { 101 }, { 110 }, { 111 }

If we take into account above:

static void subSet(char[] set) {
        int c = set.length;

        for (int i = 0; i < (1 << c); i++) {
            System.out.print("{");
            for (int j = 0; j < c; j++) {
                if ((i & (1 << j)) > 0) {
                    System.out.print(set[j] + " ");
                }
            }
            System.out.println("}");
        }
    }

    public static void main(String[] args) {
        char c[] = {'a', 'b', 'c'};
        subSet(c);
    }
Zamir
  • 449
  • 1
  • 8
  • 17
2
private static void findSubsets(int array[])
{
  int numOfSubsets = 1 << array.length; 

  for(int i = 0; i < numOfSubsets; i++)
 {
    int pos = array.length - 1;
   int bitmask = i;

   System.out.print("{");
   while(bitmask > 0)
   {
    if((bitmask & 1) == 1)
     System.out.print(array[pos]+",");
    bitmask >>= 1;
    pos--;
   }
   System.out.print("}");
 }
}
2

Based on what I learnt today, here is the Java Solution It is based on recursion

public class Powerset {

    public static void main(String[] args) {
        final List<List<String>> allSubsets = powerSet(Arrays.asList(1, 2, 3, 4), 0);
        for (List<String> subsets : allSubsets) {
            System.out.println(subsets);
        }
    }

    private static List<List<String>> powerSet(final List<Integer> values,
                                               int index) {
        if (index == values.size()) {
            return new ArrayList<>();
        }
        int val = values.get(index);
        List<List<String>> subset = powerSet(values, index + 1);
        List<List<String>> returnList = new ArrayList<>();
        returnList.add(Arrays.asList(String.valueOf(val)));
        returnList.addAll(subset);
        for (final List<String> subsetValues : subset) {
            for (final String subsetValue : subsetValues) {
                returnList.add(Arrays.asList(val + "," + subsetValue));
            }
        }
        return returnList;
    }
}

Running it will give results as

[1]
[2]
[3]
[4]
[3,4]
[2,3]
[2,4]
[2,3,4]
[1,2]
[1,3]
[1,4]
[1,3,4]
[1,2,3]
[1,2,4]
[1,2,3,4]
daydreamer
  • 87,243
  • 191
  • 450
  • 722
2
public static void printSubsets(int[] arr) {
    for (int start = 0; start < arr.length; start++) { // iterate through each element of the array
        for (int i = 0; i < arr.length - start; i++) { // find number of subsets for the element
            int[] tmp = new int[i + 1]; // calculate a temporal array size 
            for (int j = 0; j < tmp.length; j++) { // populate the array with corresponding elements
                tmp[j] = arr[start + j];
            }
            System.out.println(Arrays.toString(tmp));
        }
    }
}
1
public static ArrayList<ArrayList<Integer>> powerSet(List<Integer> intList) {

    ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
    result.add(new ArrayList<Integer>());

    for (int i : intList) {
        ArrayList<ArrayList<Integer>> temp = new ArrayList<ArrayList<Integer>>();

        for (ArrayList<Integer> innerList : result) {
            innerList = new ArrayList<Integer>(innerList);
            innerList.add(i);
            temp.add(innerList);
        }
        result.addAll(temp);
    }

    return result;
}
ThePatelGuy
  • 1,844
  • 1
  • 19
  • 18
1

I was actually trying to solve this one and got the algorithm @phimuemue on the previous post .Here is what I implemented. Hope this works.

/**
*@Sherin Syriac
*
*/

import java.util.ArrayList;
import java.util.List;

public class SubSet {
    ArrayList<List<Integer>> allSubset = new ArrayList<List<Integer>>();

    /**
     * @param args
     */
    public static void main(String[] args) {
        SubSet subSet = new SubSet();
        ArrayList<Integer> set = new ArrayList<Integer>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
        subSet.getSubSet(set, 0);
        for (List<Integer> list : subSet.allSubset) {
            System.out.print("{");
            for (Integer element : list) {
                System.out.print(element);
            }
            System.out.println("}");
        }

    }

    public void getSubSet(ArrayList<Integer> set, int index) {
        if (set.size() == index) {
            ArrayList<Integer> temp = new ArrayList<Integer>();
            allSubset.add(temp);
        } else {
            getSubSet(set, index + 1);
            ArrayList<List<Integer>> tempAllSubsets = new ArrayList<List<Integer>>();
            for (List subset : allSubset) {
                ArrayList<Integer> newList = new ArrayList<Integer>();
                newList.addAll(subset);
                newList.add(set.get(index));
                tempAllSubsets.add(newList);
            }

            allSubset.addAll(tempAllSubsets);
        }

    }

}
Sherin Syriac
  • 447
  • 6
  • 13
1

If you're dealing with a large collection of elements, you may (though not likely) run into issues with stack overflow. I admit you're more likely to run out of memory before you overflow the stack, but I will put this non-recursive method here anyway.

public static final <T> Set<Set<T>> powerSet(final Iterable<T> original) {
  Set<Set<T>> sets = new HashSet<>();
  sets.add(new HashSet<>());

  for (final T value : original) {
    final Set<Set<T>> newSets = new HashSet<>(sets);

    for (final Set<T> set : sets) {
      final Set<T> newSet = new HashSet<>(set);
      newSet.add(value);
      newSets.add(newSet);
    }

    sets = newSets;
  }

  return sets;
}

Or if you'd rather deal with arrays:

@SuppressWarnings("unchecked")
public static final <T> T[][] powerSet(final T... original) {
  T[][] sets = (T[][]) Array.newInstance(original.getClass(), 1);
  sets[0] = Arrays.copyOf(original, 0);

  for (final T value : original) {
    final int oldLength = sets.length;
    sets = Arrays.copyOf(sets, oldLength * 2);

    for (int i = 0; i < oldLength; i++) {
      final T[] oldArray = sets[i];
      final T[] newArray = Arrays.copyOf(oldArray, oldArray.length + 1);
      newArray[oldArray.length] = value;
      sets[i + oldLength] = newArray;
    }
  }

  return sets;
}
Jeff Brower
  • 594
  • 3
  • 13
1

Simple Java recursive solution -

private static List<List<Integer>> allsubSet(List<Integer> integers, int start, int end) {

       //Base case if there is only one element so there would be two subset 
       // empty list and that element
       if(start == end) {
            List<List<Integer>> result = new ArrayList<>();

            List<Integer> emptyList = new ArrayList<>();
            result.add(emptyList);

            List<Integer> element = new ArrayList<>();
            element.add(integers.get(start));
            result.add(element );

            return result;
        }
        //I know if by recursion we can expect that we'll get the n-1 correct result

       List<List<Integer>> lists = allsubSet(integers, start, end-1);

    //here i copy all the n-1 results and just added the nth element in expected results

        List<List<Integer>> copyList =  new ArrayList<>(lists);
        for (List<Integer> list : lists) {
            List<Integer> copy=  new ArrayList<>(list);
            copy.add(integers.get(end));
            copyList.add(copy);
        }
        return copyList;
    }


To avoid redundancy we can simply use Set in place of List

hims92sharma
  • 129
  • 1
  • 4
1

Get all subset using recursion (on similar lines for solving permutations from the book : Thinking recursively with Java)

public class ChapterSix {

public static void main(String[] args) {
    new ChapterSix().listSubSets("", "123");
}

void listSubSets(String prefix, String s) {
    System.out.println(prefix);

    if("".equals(s)) {
        return;
    } else {
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            String rest = s.substring(i + 1);
            listSubSets(prefix + ch, rest);
        }
    }
}
}

Output:

1
12
123
13
2
23
3
Da_Vicki
  • 91
  • 1
  • 8
1
// subsets for the set of 5,9,8

import java.util.ArrayList;
import java.util.List;

public class Subset {
    public static void main(String[] args) {
    List<Integer> s = new ArrayList<Integer>();
    s.add(9);
    s.add(5);
    s.add(8);
    int setSize = s.size();
    int finalValue = (int) (Math.pow(2, setSize));
    String bValue = "";
    for (int i = 0; i < finalValue; i++) {
        bValue = Integer.toBinaryString(i);
        int bValueSize = bValue.length();
        for (int k = 0; k < (setSize - bValueSize); k++) {
            bValue = "0" + bValue;
        }
        System.out.print("{ ");
        for (int j = 0; j < setSize; j++) {
            if (bValue.charAt(j) == '1') {
                System.out.print((s.get(j)) + " ");
            }
        }
        System.out.print("} ");
    }
}
}


//Output : { } { 8 } { 5 } { 5 8 } { 9 } { 9 8 } { 9 5 } { 9 5 8 } 
0

Here's some pseudocode. You can cut same recursive calls by storing the values for each call as you go and before recursive call checking if the call value is already present.

The following algorithm will have all the subsets excluding the empty set.

list * subsets(string s, list * v){
    if(s.length() == 1){
        list.add(s);    
        return v;
    }
    else
    {
        list * temp = subsets(s[1 to length-1], v);     
        int length = temp->size();

        for(int i=0;i<length;i++){
            temp.add(s[0]+temp[i]);
        }

        list.add(s[0]);
        return temp;
    }
}
eldarerathis
  • 35,455
  • 10
  • 90
  • 93
kofhearts
  • 3,607
  • 8
  • 46
  • 79
0

Here's the logic to print all the subsets of a given set of numbers. This is also called powerset of a set. I have used a simple recursive approach to solve this using Java, but you can correspondingly code in other languages as well.

import java.util.Scanner;

public class PowerSubset {

    public static void main(String[] args) {

        // HardCoded Input
         int arr[] = { 1, 2, 3 };//original array whose subset is to be found
         int n=3; //size of array

        // Dynamic Input
        /*Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int arr[] = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }*/

        int data[] = new int[arr.length]; // temporary array

        printSubset(arr, data, n, 0, 0);
    }

    public static void printSubset(int arr[], int data[], int n, int dataIndex, int arrIndex) {
        if (arrIndex == n) { //comparing with n since now you are at the leaf node
            System.out.print("[");//watch pictorial chart in the below video link 
            for (int j = 0; j < n; j++) {
                System.out.print(data[j] == 0 ? "" : data[j]);
            }
            System.out.print("]");
            System.out.println();
            return;
        }
        data[dataIndex] = arr[arrIndex];
        printSubset(arr, data, n, dataIndex + 1, arrIndex + 1);//recursive call 1
        data[dataIndex] = 0;
        printSubset(arr, data, n, dataIndex, arrIndex + 1);//recursive call 2
    }

}

Output of the above code:

[123]
[12]
[13]
[1]
[23]
[2]
[3]
[]