数字のセットのすべてのサブセットを計算する
質問
一連の整数のサブセットを見つけたいです。これは、バックトラッキングを備えた「サブセットの合計」アルゴリズムの最初のステップです。次のコードを書きましたが、正解は返されません。
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;
}
たとえば、set = {1、3、5}のサブセットを計算する場合、私の方法の結果は次のとおりです。
1, 3, 5, ********************
5, ********************
3, 5, ********************
5, ********************
3, 5, ********************
5, ********************
私はそれが生産したいです:
1, 3, 5
1, 5
3, 5
5
問題は部品list.RemoveAll(リスト)からだと思います。しかし、私はそれを修正する方法を知りません。
解決
あなたが望むものはaと呼ばれます パワーセット. 。これが簡単な実装です:
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;
}
アルゴリズムがパワーセットのためにどのように機能するかを説明する例を挙げます {1, 2, 3}
:
- 削除する
{1}
, 、およびパワーセットを実行します{2, 3}
;- 削除する
{2}
, 、およびパワーセットを実行します{3}
;- 削除する
{3}
, 、およびパワーセットを実行します{}
;- のパワーセット
{}
は{{}}
;
- のパワーセット
- のパワーセット
{3}
は3
と組み合わせ{{}}
={ {}, {3} }
;
- 削除する
- のパワーセット
{2, 3}
は{2}
と組み合わせ{ {}, {3} }
={ {}, {3}, {2}, {2, 3} }
;
- 削除する
- のパワーセット
{1, 2, 3}
は{1}
と組み合わせ{ {}, {3}, {2}, {2, 3} }
={ {}, {3}, {2}, {2, 3}, {1}, {3, 1}, {2, 1}, {2, 3, 1} }
.
他のヒント
あなたの方法だけです たぶん......だろう 問題を解く:
アプローチ1
- 番号リストの最初の要素を取ります
- 生む すべて 残りの番号リストからのサブセット(つまり、選択したものなしの番号リスト=>再帰!
- 前のステップで見つかったすべてのサブセットについて、サブセット自体を追加し、ステップ1で選択した要素に合わせて出力に合わせます。
もちろん、基本ケース、つまり番号リストが空の場合は確認する必要があります。
アプローチ2
それはよく知られている事実です n
要素があります 2^n
サブセット。したがって、からバイナリでカウントできます 0
に 2^n
バイナリ番号を対応するサブセットとして解釈します。このアプローチには、セット全体を表すのに十分な桁を持つバイナリ番号が必要であることに注意してください。
2つのアプローチのいずれかをコードに変換するのは、それほど大きな問題ではないはずです。
あなたのコードは本当に混乱しており、説明はありません。
セットにある数値を決定するビットマスクで繰り返し行うことができます。 0〜2^nの各数値は、たとえば、そのバイナリ表現に一意のサブセットを提供します。
n = 3の場合:
i = 5-> 101バイナリで、最初と最後の要素を選択しますi = 7-> 111バイナリで、最初の3つの要素を選択します
n要素があると仮定します(n <64、結局、nが64を超える場合、あなたは永遠に実行されます)。
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
}
この質問に対するnoobの訪問者(Googleに感謝します)を考慮してください - 私のような
これは、単純なプリンシパルで機能する再帰ソリューションです。
set = {a、b、c、d、e}
それから私たちはそれを壊すことができます {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
}
}
出力
a
ab
abc
abcd
abd
ac
acd
ad
b
bc
bcd
bd
c
cd
d
特定のセットのサブセットの総数が2^(セット内の要素の数)に等しいことは明らかです。設定されている場合
a = {1、2、3}
次に、Aのサブセット:
{ }, { 1 }, { 2 }, { 3 }, { 1, 2 }, { 1, 3 }, { 2, 3 }, { 1, 2, 3 }
私たちが見るなら、それはバイナリ番号のようなものです。
{ 000 }, { 001 }, { 010 }, { 011 }, { 100 }, { 101 }, { 110 }, { 111 }
上記で考慮した場合:
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);
}
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("}");
}
}
私が今日学んだことに基づいて、ここに基づいているJavaソリューションがあります 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;
}
}
実行すると結果が得られます
[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]
私は実際にこれを解決しようとしていて、前の投稿で@phimuemueを手に入れました。ここで実装したものです。これがうまくいくことを願っています。
/**
*@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);
}
}
}
// 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 }
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;
}
要素の大規模なコレクションを扱っている場合、スタックオーバーフローの問題に遭遇する可能性があります。スタックにオーバーフローする前に、あなたがメモリが尽きる可能性が高いことを認めていますが、とにかくこの非再帰的な方法をここに置きます。
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;
}
または、配列を扱いたい場合は:
@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;
}
ここにいくつかの擬似コードがあります。通話ごとに各コールの値を保存することにより、および呼び出し値が既に存在しているかどうかを再帰的なコールチェックの前に、同じ再帰コールを削減できます。
次のアルゴリズムには、空のセットを除くすべてのサブセットがあります。
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;
}
}
特定の数値セットのすべてのサブセットを印刷するロジックは次のとおりです。これは、セットのPowerSetとも呼ばれます。 Javaを使用してこれを解決するために簡単な再帰アプローチを使用しましたが、それに応じて他の言語でもコードできます。
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
}
}
上記のコードの出力:
[123]
[12]
[13]
[1]
[23]
[2]
[3]
[]
コンセプトを取得するには、コードの背後にあるアプローチを明確に説明する次のYouTubeビデオを見ることができます。https://www.youtube.com/watch?v=vel15c3vbve
シンプルなJava再帰ソリューション -
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;
}
冗長性を回避するために、リストの代わりにセットを使用することができます