Reputation:
I'm trying to find an efficient manner to generate a powerset of a set that has the subsets of a certain size k. I have found answers of how to generate all powersets and powersets within a range, but I'm not sure how I would do it if I only wanted one certain size.
thanks!
Upvotes: 4
Views: 1537
Reputation: 6138
Try this to generate the power set of the set:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class GeneratePowerSet {
public static <T> Set<Set<T>> powerSet(Set<T> originalSet) {
Set<Set<T>> sets = new HashSet<>();
if (originalSet.isEmpty()) {
sets.add(new HashSet<T>());
return sets;
}
List<T> list = new ArrayList<>(originalSet);
T head = list.get(0);
Set<T> rest = new HashSet<>(list.subList(1, list.size()));
for (Set<T> set : powerSet(rest)) {
Set<T> newSet = new HashSet<>();
newSet.add(head);
newSet.addAll(set);
sets.add(newSet);
sets.add(set);
}
return sets;
}
public static void main(String args[]) {
Set<Integer> mySet = new HashSet<Integer>();
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(4);
for (Set<Integer> s : powerSet(mySet)) {
System.out.println(s);
}
}
}
For more information, visit https://github.com/m-vahidalizadeh/foundations/blob/master/src/algorithms/GeneratePowerSet.java. I hope it helps.
Upvotes: 0
Reputation: 37645
This works by converting the set into a list and iterating through all possible combinations of indices.
static <E> Set<Set<E>> subsets(Set<E> set, int n) {
if (n < 0)
throw new IllegalArgumentException();
Set<Set<E>> temp = new HashSet<>();
int size = set.size();
if (n > size)
return temp;
List<E> list = new ArrayList<>(set);
int[] indices = new int[n];
for (int i = 0; i < n; i++)
indices[i] = i;
while (true) {
Set<E> s = new HashSet<>();
for (int i : indices)
s.add(list.get(i));
temp.add(s);
int r = n - 1;
for (int m = size; r >= 0 && indices[r] == --m; r--);
if (r == -1)
return temp;
for (int c = indices[r]; r < n;)
indices[r++] = ++c;
}
}
Upvotes: 0
Reputation: 4356
You can use simple backtracking to do this. You just go over each element and either pick this element to be in your subset or not. At the same time you can keep track of the current subset your are trying to build (current_subset
) and how many elements you can still pick (k
). A sample implementation:
static <E> void backtrack(int index, int k, Deque<E> current_subset,
List<E> elements)
{
if (k == 0) {
System.out.println(current_subset);
return;
}
if (index == elements.size())
return;
current_subset.push(elements.get(index));
backtrack(index + 1, k - 1, current_subset, elements);
current_subset.pop();
backtrack(index + 1, k, current_subset, elements);
}
backtrack(0, 2, new ArrayDeque<Integer>(),
Arrays.asList(new Integer[]{0, 1, 2, 3, 4}));
/*
[1, 0]
[2, 0]
[3, 0]
[4, 0]
[2, 1]
[3, 1]
[4, 1]
[3, 2]
[4, 2]
*/
Note that if you what to keep the subsets you can just insert them in some structure (such as a List
) instead of printing them.
Upvotes: 0
Reputation: 34829
Create a list containing the elements of the set.
Create a second list consisting of only 1's and 0's, where
k
For each permutation of the second list, the subset consists of the elements from the first list whose corresponding entry in the second list is a 1.
Upvotes: 1