整数セットのサブセットを見つけたい。これは、バックトラッキングを使用した「サブセットの合計」アルゴリズムの最初のステップです。次のコードを作成しましたが、正しい答えが返されません。
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
問題は部品リストにあると思います。removeAll(list);しかし、私はそれを修正する方法を知りません。
必要なものはPowersetと呼ばれます。以下に簡単な実装を示します。
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}
のpowersetに対してアルゴリズムがどのように機能するかを説明する例を示します。
{1}
を削除し、{2, 3}
;のpowersetを実行します。{2}
を削除し、{3}
;のpowersetを実行します。{3}
を削除し、{}
;のpowersetを実行します。{}
のパワーセットは{{}}
です。{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} }
です。could問題の解決方法の入門書:
もちろん、ベースケースをチェックする必要があります。つまり、番号リストが空であるかどうかです。
n
要素を持つセットが2^n
サブセットを持つことはよく知られた事実です。したがって、0
から2^n
までのバイナリでカウントし、バイナリ番号を対応するサブセットとして解釈できます。このアプローチでは、セット全体を表すのに十分な桁数の2進数が必要であることに注意してください。
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訪問者(グーグルのおかげ)を検討-私のように
これは、単純なプリンシパルで機能する再帰的なソリューションです。
セット= {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
}
}
[〜#〜] output [〜#〜]
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}
見てみると、2進数のようなものです。
{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);
}
今日学んだことに基づいて、Java Solutionは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]
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("}");
}
}
私は実際にこれを解決しようとしており、前の投稿でアルゴリズム@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);
}
}
}
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;
}
// 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 }
以下に、特定の数値セットのすべてのサブセットを出力するロジックを示します。これはセットの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
疑似コードを次に示します。呼び出し値が既に存在する場合、再帰呼び出しチェックの前に、各呼び出しの値を保存することにより、同じ再帰呼び出しをカットできます。
次のアルゴリズムには、空のセットを除くすべてのサブセットが含まれます。
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;
}
}