{1, 2, 3}
のパワーセットは次のとおりです。
{{}, {2}, {3}, {2, 3}, {1, 2}, {1, 3}, {1, 2, 3}, {1}}
JavaにSet
があるとします。
Set<Integer> mySet = new HashSet<Integer>();
mySet.add(1);
mySet.add(2);
mySet.add(3);
Set<Set<Integer>> powerSet = getPowerset(mySet);
可能な限り複雑な順序でgetPowerset関数を作成するにはどうすればよいですか? (O(2 ^ n)かもしれません。)
はい、それはO(2^n)
です。実際に生成する必要があるので、2^n
可能な組み合わせ。ジェネリックとセットを使用した実用的な実装を次に示します。
public static <T> Set<Set<T>> powerSet(Set<T> originalSet) {
Set<Set<T>> sets = new HashSet<Set<T>>();
if (originalSet.isEmpty()) {
sets.add(new HashSet<T>());
return sets;
}
List<T> list = new ArrayList<T>(originalSet);
T head = list.get(0);
Set<T> rest = new HashSet<T>(list.subList(1, list.size()));
for (Set<T> set : powerSet(rest)) {
Set<T> newSet = new HashSet<T>();
newSet.add(head);
newSet.addAll(set);
sets.add(newSet);
sets.add(set);
}
return sets;
}
そして、サンプル入力を与えられたテスト:
Set<Integer> mySet = new HashSet<Integer>();
mySet.add(1);
mySet.add(2);
mySet.add(3);
for (Set<Integer> s : SetUtils.powerSet(mySet)) {
System.out.println(s);
}
実際、私はあなたがO(1)で求めていることをするコードを書きました。問題は、次に設定するdoの計画です。単にsize()
を呼び出す場合はO(1)ですが、反復する場合は明らかにO(2^n)
です。
contains()
はO(n)
などになります。
これは本当に必要ですか?
編集:
このコードは 現在グアバで利用可能 で、メソッド Sets.powerSet(set)
で公開されています。
発電機を使用するソリューションは次のとおりです。利点は、電源セット全体が一度に保存されることはないということです。したがって、メモリに保存する必要なく、1つずつ繰り返し処理できます。私はそれがより良いオプションだと思いたい...複雑さは同じであることに注意してください、O(2 ^ n)、しかしメモリ要件は減ります(ガベージコレクタが振る舞うと仮定して!;))
/**
*
*/
package org.mechaevil.util.Algorithms;
import Java.util.BitSet;
import Java.util.Iterator;
import Java.util.Set;
import Java.util.TreeSet;
/**
* @author st0le
*
*/
public class PowerSet<E> implements Iterator<Set<E>>,Iterable<Set<E>>{
private E[] arr = null;
private BitSet bset = null;
@SuppressWarnings("unchecked")
public PowerSet(Set<E> set)
{
arr = (E[])set.toArray();
bset = new BitSet(arr.length + 1);
}
@Override
public boolean hasNext() {
return !bset.get(arr.length);
}
@Override
public Set<E> next() {
Set<E> returnSet = new TreeSet<E>();
for(int i = 0; i < arr.length; i++)
{
if(bset.get(i))
returnSet.add(arr[i]);
}
//increment bset
for(int i = 0; i < bset.size(); i++)
{
if(!bset.get(i))
{
bset.set(i);
break;
}else
bset.clear(i);
}
return returnSet;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not Supported!");
}
@Override
public Iterator<Set<E>> iterator() {
return this;
}
}
呼び出すには、次のパターンを使用します。
Set<Character> set = new TreeSet<Character> ();
for(int i = 0; i < 5; i++)
set.add((char) (i + 'A'));
PowerSet<Character> pset = new PowerSet<Character>(set);
for(Set<Character> s:pset)
{
System.out.println(s);
}
それは私のプロジェクトオイラーライブラリから... :)
N <63の場合、(イテレータ実装を使用しない限り)メモリセットが不足するため、とにかくパワーセットを構築しようとするので、これはより簡潔な方法です。バイナリ操作はMath.pow()
やマスクの配列よりも高速ですが、どういうわけかJavaユーザーはそれらを恐れています...
List<T> list = new ArrayList<T>(originalSet);
int n = list.size();
Set<Set<T>> powerSet = new HashSet<Set<T>>();
for( long i = 0; i < (1 << n); i++) {
Set<T> element = new HashSet<T>();
for( int j = 0; j < n; j++ )
if( (i >> j) % 2 == 1 ) element.add(list.get(j));
powerSet.add(element);
}
return powerSet;
ここ は、コードを含め、必要なものを正確に説明するチュートリアルです。複雑さはO(2 ^ n)であるという点で正しいです。
@Harry Heのアイデアに基づいた別のソリューションを思いつきました。おそらく最もエレガントではありませんが、ここで私が理解しているとおりです:
S P(S) = {{1}、{2}、{3}}の古典的な単純な例のPowerSetを見てみましょう。サブセットの数を取得する式は2 ^ n(7 +空のセット)この例では、2 ^ 3 = 8個のサブセットです。
各サブセットを見つけるには、以下の変換表に示す0〜7の10進数を2進数に変換する必要があります。
テーブルを行ごとに走査すると、各行はサブセットになり、各サブセットの値は有効なビットから取得されます。
[ビンの値]セクションの各列は、元の入力セットのインデックス位置に対応しています。
ここに私のコード:
public class PowerSet {
/**
* @param args
*/
public static void main(String[] args) {
PowerSet ps = new PowerSet();
Set<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
for (Set<Integer> s : ps.powerSet(set)) {
System.out.println(s);
}
}
public Set<Set<Integer>> powerSet(Set<Integer> originalSet) {
// Original set size e.g. 3
int size = originalSet.size();
// Number of subsets 2^n, e.g 2^3 = 8
int numberOfSubSets = (int) Math.pow(2, size);
Set<Set<Integer>> sets = new HashSet<Set<Integer>>();
ArrayList<Integer> originalList = new ArrayList<Integer>(originalSet);
for (int i = 0; i < numberOfSubSets; i++) {
// Get binary representation of this index e.g. 010 = 2 for n = 3
String bin = getPaddedBinString(i, size);
//Get sub-set
Set<Integer> set = getSet(bin, originalList));
sets.add(set);
}
return sets;
}
//Gets a sub-set based on the binary representation. E.g. for 010 where n = 3 it will bring a new Set with value 2
private Set<Integer> getSet(String bin, List<Integer> origValues){
Set<Integer> result = new HashSet<Integer>();
for(int i = bin.length()-1; i >= 0; i--){
//Only get sub-sets where bool flag is on
if(bin.charAt(i) == '1'){
int val = origValues.get(i);
result.add(val);
}
}
return result;
}
//Converts an int to Bin and adds left padding to zero's based on size
private String getPaddedBinString(int i, int size) {
String bin = Integer.toBinaryString(i);
bin = String.format("%0" + size + "d", Integer.parseInt(bin));
return bin;
}
}
Eclipse Collections (以前の GS Collections )を使用している場合、すべてのSetIterablesでpowerSet()
メソッドを使用できます。
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]]
注:私はEclipse Collectionsのコミッターです。
ここに掲載されているものほど大きくないソリューションを探していました。これはJava 7を対象としているため、バージョン5および6には少数のペーストが必要になります。
Set<Set<Object>> powerSetofNodes(Set<Object> orig) {
Set<Set<Object>> powerSet = new HashSet<>(),
runSet = new HashSet<>(),
thisSet = new HashSet<>();
while (powerSet.size() < (Math.pow(2, orig.size())-1)) {
if (powerSet.isEmpty()) {
for (Object o : orig) {
Set<Object> s = new TreeSet<>();
s.add(o);
runSet.add(s);
powerSet.add(s);
}
continue;
}
for (Object o : orig) {
for (Set<Object> s : runSet) {
Set<Object> s2 = new TreeSet<>();
s2.addAll(s);
s2.add(o);
powerSet.add(s2);
thisSet.add(s2);
}
}
runSet.clear();
runSet.addAll(thisSet);
thisSet.clear();
}
powerSet.add(new TreeSet());
return powerSet;
テストするコードの例を次に示します。
Set<Object> hs = new HashSet<>();
hs.add(1);
hs.add(2);
hs.add(3);
hs.add(4);
for(Set<Object> s : powerSetofNodes(hs)) {
System.out.println(Arrays.toString(s.toArray()));
}
簡単な反復O(2 ^ n)ソリューションを次に示します。
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;
}
次のソリューションは、私の本「 コーディングインタビュー:質問、分析、ソリューション 」から引用したものです。
配列内のいくつかの整数が選択され、組み合わせが構成されます。ビットのセットが使用されます。各ビットは配列内の整数を表します。 i-th文字が組み合わせに選択されている場合、i-thビットは1です。それ以外の場合は0です。たとえば、配列[1、2、3]の組み合わせには3ビットが使用されます。最初の2つの整数1と2を選択して組み合わせ[1、2]を構成する場合、対応するビットは{1、1、0}です。同様に、別の組み合わせ[1、3]に対応するビットは{1、0、1}です。 nビットのすべての可能な組み合わせを取得できる場合、長さnの配列のすべての組み合わせを取得できます。
数値はビットのセットで構成されます。 nビットのすべての可能な組み合わせは、1から2 ^n-1の数字に対応します。したがって、1から2 ^n-1の範囲の各数値は、長さnの配列の組み合わせに対応します。たとえば、数字6はビット{1、1、0}で構成されているため、配列[1、2、3]で最初と2番目の文字が選択され、組み合わせ[1、2]が生成されます。同様に、ビット{1、0、1}の数字5は、組み合わせ[1、3]に対応します。
このソリューションを実装するためのJavaコードは次のようになります。
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;
}
メソッドのインクリメントは、ビットのセットで表される数を増やします。アルゴリズムは、0ビットが見つかるまで右端のビットから1ビットをクリアします。次に、右端の0ビットを1に設定します。たとえば、ビット{1、0、1}で5を増やすために、右側から1ビットをクリアし、右端の0ビットを1に設定します。数字6の{1、1、0}。これは5を1増やした結果です。
上記のソリューションのいくつかは、セットのサイズが大きいと、収集するオブジェクトガベージが大量に作成され、データのコピーが必要になるため、問題が発生します。どうすればそれを回避できますか?結果セットのサイズがどれだけ大きくなるか(2 ^ n)を知っているという事実を利用し、その配列を事前に割り当てて、コピーせずに最後に追加するだけです。
スピードアップはnで急速に成長します。上記のJoãoSilvaのソリューションと比較しました。私のマシンでは(すべての測定値が近似)、n = 13は5倍、n = 14は7倍、n = 15は12倍、n = 16は25倍、n = 17は75倍、n = 18は140倍です。そのため、ガベージの作成/収集とコピーは、他の点では同様のbig-Oソリューションと思われるものを支配しています。
最初に配列を事前に割り当てることは、動的に成長させるのに比べて利点があります。 n = 18の場合、動的な成長には全体で約2倍の時間がかかります。
public static <T> List<List<T>> powerSet(List<T> 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<List<T>> resultPowerSet = new ArrayList<List<T>>(resultSize);
// Initialize result with the empty set, which powersets contain by definition
resultPowerSet.add(new ArrayList<T>(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<startingResultSize; i++) {
// start with an existing element of the powerset
List<T> oldSubset = resultPowerSet.get(i);
// create a new element by adding a new item from the original list
List<T> newSubset = new ArrayList<T>(oldSubset);
newSubset.add(itemFromOriginalSet);
// add this element to the result powerset (past startingResultSize)
resultPowerSet.add(newSubset);
}
}
return resultPowerSet;
}
import Java.util.Set;
import com.google.common.collect.*;
Set<Set<Integer>> sets = Sets.powerSet(ImmutableSet.of(1, 2, 3));
これがラムダに関する私のアプローチです。
public static <T> Set<Set<T>> powerSet(T[] set) {
return IntStream
.range(0, (int) Math.pow(2, set.length))
.parallel() //performance improvement
.mapToObj(e -> IntStream.range(0, set.length).filter(i -> (e & (0b1 << i)) != 0).mapToObj(i -> set[i]).collect(Collectors.toSet()))
.map(Function.identity())
.collect(Collectors.toSet());
}
または並行して(parallel()コメントを参照):
入力セットのサイズ:18
論理プロセッサー:8à3.4GHz
パフォーマンスの改善:30%
これは、Java Generics。次のように。
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);
}
}
これは出力します:
[[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], []]
SがN個の要素を持つ有限集合である場合、Sのべき集合には2 ^ N個の要素が含まれます。 powersetの要素を単純に列挙する時間は2 ^ Nなので、O(2^N)
は(熱心に)powersetを構築する時間の複雑さの下限です。
簡単に言えば、パワーセットの作成を伴う計算は、Nの大きな値に対してスケーリングされません。パワーセットを作成する必要を回避することを除けば、賢いアルゴリズムは役に立ちません。
再帰なしの1つの方法は次のとおりです。バイナリマスクを使用して、可能なすべての組み合わせを作成します。
public HashSet<HashSet> createPowerSet(Object[] array)
{
HashSet<HashSet> powerSet=new HashSet();
boolean[] mask= new boolean[array.length];
for(int i=0;i<Math.pow(2, array.length);i++)
{
HashSet set=new HashSet();
for(int j=0;j<mask.length;j++)
{
if(mask[i])
set.add(array[j]);
}
powerSet.add(set);
increaseMask(mask);
}
return powerSet;
}
public void increaseMask(boolean[] mask)
{
boolean carry=false;
if(mask[0])
{
mask[0]=false;
carry=true;
}
else
mask[0]=true;
for(int i=1;i<mask.length;i++)
{
if(mask[i]==true && carry==true)
mask[i]=false;
else if (mask[i]==false && carry==true)
{
mask[i]=true;
carry=false;
}
else
break;
}
}
アルゴリズム:
入力:Set []、set_size 1.パワーセットのサイズを取得します。powet_set_size = pow(2、set_size)2 0からpow_set_sizeまでのカウンターのループ(a)i = 0からset_sizeのループ(i)カウンターのi番目のビットがsetこのサブセットのセットからi番目の要素を出力(b)サブセットのセパレータを出力、つまり改行
#include <stdio.h>
#include <math.h>
void printPowerSet(char *set, int set_size)
{
/*set_size of power set of a set with set_size
n is (2**n -1)*/
unsigned int pow_set_size = pow(2, set_size);
int counter, j;
/*Run from counter 000..0 to 111..1*/
for(counter = 0; counter < pow_set_size; counter++)
{
for(j = 0; j < set_size; j++)
{
/* Check if jth bit in the counter is set
If set then pront jth element from set */
if(counter & (1<<j))
printf("%c", set[j]);
}
printf("\n");
}
}
/*Driver program to test printPowerSet*/
int main()
{
char set[] = {'a','b','c'};
printPowerSet(set, 3);
getchar();
return 0;
}
別のサンプル実装:
public static void main(String args[])
{
int[] arr = new int[]{1,2,3,4};
// Assuming that number of sets are in integer range
int totalSets = (int)Math.pow(2,arr.length);
for(int i=0;i<totalSets;i++)
{
String binaryRep = Integer.toBinaryString(i);
for(int j=0;j<binaryRep.length();j++)
{
int index=binaryRep.length()-1-j;
if(binaryRep.charAt(index)=='1')
System.out.print(arr[j] +" ");
}
System.out.println();
}
}
Tのサブセットは、tのゼロ個以上の要素を削除することで作成できる任意のセットです。 withoutFirstサブセットは、最初の要素が欠落しているtのサブセットを追加し、forループは最初の要素を持つサブセットの追加を処理します。たとえば、tに要素["1"、 "2"、 "3"]が含まれている場合、missingFirstは[[""]、["2"]、["3"]、["2"、 "3を追加します"]]およびforループは、これらの要素の前に" 1 "を貼り付け、newSetに追加します。したがって、[[""]、["1"]、["2"]、["3"]、["1"、 "2"]、["1"、 "3"]になります。 、["2"、 "3"]、["1"、 "2"、 "3"]]。
public static Set<Set<String>> allSubsets(Set<String> t) {
Set<Set<String>> powerSet = new TreeSet<>();
if(t.isEmpty()) {
powerSet.add(new TreeSet<>());
return powerSet;
}
String first = t.get(0);
Set<Set<String>> withoutFirst = allSubsets(t.subSet(1, t.size()));
for (List<String> 1st : withoutFirst) {
Set<String> newSet = new TreeSet<>();
newSet.add(first);
newSet.addAll(lst);
powerSet.add(newSet);
}
powerSet.addAll(withoutFirst);
return powerSet;
}
私は最近このようなものを使用する必要がありましたが、最初に最小のサブリスト(1つの要素、次に2つの要素、...)が必要でした。空のリストもリスト全体も含めたくありませんでした。また、返されたすべてのサブリストのリストは必要ありませんでしたが、それぞれについていくつかの作業を行う必要がありました。
再帰なしでこれをやりたいと思って、次のものを考え出しました(機能的なインターフェースに抽象化された「やること」):
@FunctionalInterface interface ListHandler<T> {
void handle(List<T> list);
}
public static <T> void forAllSubLists(final List<T> list, ListHandler handler) {
int ll = list.size(); // Length of original list
int ci[] = new int[ll]; // Array for list indices
List<T> sub = new ArrayList<>(ll); // The sublist
List<T> uml = Collections.unmodifiableList(sub); // For passing to handler
for (int gl = 1, gm; gl <= ll; gl++) { // Subgroup length 1 .. n-1
gm = 0; ci[0] = -1; sub.add(null); // Some inits, and ensure sublist is at least gl items long
do {
ci[gm]++; // Get the next item for this member
if (ci[gm] > ll - gl + gm) { // Exhausted all possibilities for this position
gm--; continue; // Continue with the next value for the previous member
}
sub.set(gm, list.get(ci[gm])); // Set the corresponding member in the sublist
if (gm == gl - 1) { // Ok, a sublist with length gl
handler.handle(uml); // Handle it
} else {
ci[gm + 1] = ci[gm]; // Starting value for next member is this
gm++; // Continue with the next member
}
} while (gm >= 0); // Finished cycling through all possibilities
} // Next subgroup length
}
このように、特定の長さのサブリストに制限することも簡単です。
public class PowerSet {
public static List<HashSet<Integer>> powerset(int[] a) {
LinkedList<HashSet<Integer>> sets = new LinkedList<HashSet<Integer>>();
int n = a.length;
for (int i = 0; i < 1 << n; i++) {
HashSet<Integer> set = new HashSet<Integer>();
for (int j = 0; j < n; j++) {
if ((1 << j & i) > 0)
set.add(a[j]);
}
sets.add(set);
}
return sets;
}
public static void main(String[] args) {
List<HashSet<Integer>> sets = PowerSet.powerset(new int[]{ 1, 2, 3 });
for (HashSet<Integer> set : sets) {
for (int i : set)
System.out.print(i);
System.out.println();
}
}
}
さらに別のソリューション-Java8 +ストリーミングAPIを使用する遅延および順序付けされているため、「limit()」で使用すると正しいサブセットが返されます。
public long bitRangeMin(int size, int bitCount){
BitSet bs = new BitSet(size);
bs.set(0, bitCount);
return bs.toLongArray()[0];
}
public long bitRangeMax(int size, int bitCount){
BitSet bs = BitSet.valueOf(new long[]{0});
bs.set(size - bitCount, size);
return bs.toLongArray()[0];
}
public <T> Stream<List<T>> powerSet(Collection<T> data)
{
List<T> list = new LinkedHashSet<>(data).stream().collect(Collectors.toList());
Stream<BitSet> head = LongStream.of(0).mapToObj( i -> BitSet.valueOf(new long[]{i}));
Stream<BitSet> tail = IntStream.rangeClosed(1, list.size())
.boxed()
.flatMap( v1 -> LongStream.rangeClosed( bitRangeMin(list.size(), v1), bitRangeMax(list.size(), v1))
.mapToObj(v2 -> BitSet.valueOf(new long[]{v2}))
.filter( bs -> bs.cardinality() == v1));
return Stream.concat(head, tail)
.map( bs -> bs
.stream()
.mapToObj(list::get)
.collect(Collectors.toList()));
}
そして、クライアントコードは
@Test
public void testPowerSetOfGivenCollection(){
List<Character> data = new LinkedList<>();
for(char i = 'a'; i < 'a'+5; i++ ){
data.add(i);
}
powerSet(data)
.limit(9)
.forEach(System.out::print);
}
/ *印刷:[] [a] [b] [c] [d] [e] [a、b] [a、c] [b、c] * /
再帰を使用してもしなくても、パワーセットを記述できます。ここに再帰なしの試みがあります:
public List<List<Integer>> getPowerSet(List<Integer> set) {
List<List<Integer>> powerSet = new ArrayList<List<Integer>>();
int max = 1 << set.size();
for(int i=0; i < max; i++) {
List<Integer> subSet = getSubSet(i, set);
powerSet.add(subSet);
}
return powerSet;
}
private List<Integer> getSubSet(int p, List<Integer> set) {
List<Integer> subSet = new ArrayList<Integer>();
int position = 0;
for(int i=p; i > 0; i >>= 1) {
if((i & 1) == 1) {
subSet.add(set.get(position));
}
position++;
}
return subSet;
}
// input: S
// output: P
// S = [1,2]
// P = [], [1], [2], [1,2]
public static void main(String[] args) {
String input = args[0];
String[] S = input.split(",");
String[] P = getPowerSet(S);
if (P.length == Math.pow(2, S.length)) {
for (String s : P) {
System.out.print("[" + s + "],");
}
} else {
System.out.println("Results are incorrect");
}
}
private static String[] getPowerSet(String[] s) {
if (s.length == 1) {
return new String[] { "", s[0] };
} else {
String[] subP1 = getPowerSet(Arrays.copyOfRange(s, 1, s.length));
String[] subP2 = new String[subP1.length];
for (int i = 0; i < subP1.length; i++) {
subP2[i] = s[0] + subP1[i];
}
String[] P = new String[subP1.length + subP2.length];
System.arraycopy(subP1, 0, P, 0, subP1.length);
System.arraycopy(subP2, 0, P, subP1.length, subP2.length);
return P;
}
}
ここでは、パワーセットを生成します。アイデアは最初= S[0]
およびそれより小さいセットはS[1,...n]
。
SmallSetのすべてのサブセットを計算し、それらをすべてのサブセットに入れます。
すべてのサブセットのサブセットごとに、クローンを作成し、最初にサブセットに追加します。
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;
}