web-dev-qa-db-fra.com

Calculer tous les sous-ensembles d'un ensemble de nombres

Je veux trouver les sous-ensembles d'un ensemble d'entiers. C'est la première étape de l'algorithme "Sum of Subsets" avec retour en arrière. J'ai écrit le code suivant, mais il ne renvoie pas la réponse correcte:

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;
}

Par exemple, si je veux calculer les sous-ensembles de set = {1, 3, 5} .__, le résultat de ma méthode est le suivant:

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

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

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

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

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

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

Je veux qu'il produise:

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

Je pense que le problème vient de la partie List.removeAll (list); Mais je ne sais pas comment le corriger.

37
Elton.fd

Ce que vous voulez s'appelle un Powerset. Voici une implémentation simple de celle-ci:

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;
    }

Je vais vous donner un exemple pour expliquer le fonctionnement de l'algorithme pour l'ensemble de pouvoir de {1, 2, 3}:

  • Supprimez {1} et exécutez powerset pour {2, 3};
    • Supprimez {2} et exécutez powerset pour {3};
      • Supprimez {3} et exécutez powerset pour {};
        • Powerset de {} est {{}};
      • L'ensemble de pouvoir de {3} est 3 combiné avec {{}} = { {}, {3} };
    • L'ensemble de pouvoir de {2, 3} est {2} combiné avec { {}, {3} } = { {}, {3}, {2}, {2, 3} };
  • L'ensemble de pouvoir de {1, 2, 3} est {1} combiné avec { {}, {3}, {2}, {2, 3} } = { {}, {3}, {2}, {2, 3}, {1}, {3, 1}, {2, 1}, {2, 3, 1} }.
83
João Silva

Juste une introduction comment vous pourriez résoudre le problème:

Approche 1

  • Prenez le premier élément de votre liste de numéros
  • générer tous sous-ensembles à partir de la liste de numéros restante (c'est-à-dire la liste de numéros sans celle choisie) => récursion!
  • pour chaque sous-ensemble trouvé à l'étape précédente, ajoutez le sous-ensemble lui-même et le sous-ensemble associé à l'élément choisi à l'étape 1 dans la sortie.

Bien sûr, vous devez vérifier le cas de base, c’est-à-dire si votre liste de numéros est vide. 

Approche 2

C'est un fait bien connu qu'un ensemble avec des éléments n a des sous-ensembles 2^n. Ainsi, vous pouvez compter en binaire de 0 à 2^n et interpréter le nombre binaire comme le sous-ensemble correspondant. Notez que cette approche nécessite un nombre binaire avec un nombre suffisant de chiffres pour représenter l'ensemble.

Convertir l’une des deux approches en code ne devrait pas être un gros problème.

21
phimuemue

Votre code est vraiment déroutant et il n'y a pas d'explication. 

Vous pouvez le faire de manière itérative avec un masque de bits qui détermine les nombres figurant dans l'ensemble. Chaque nombre de 0 à 2 ^ n donne un sous-ensemble unique dans sa représentation binaire, par exemple

pour n = 3:

i = 5 -> 101 en binaire, choisissez le premier et le dernier élément i = 7 -> 111 en binaire, choisissez les 3 premiers éléments

Supposons qu'il y ait n éléments (n <64, après tout si n est supérieur à 64, vous exécuterez cela pour toujours).

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
}
15
Piva

Considérant un visiteur de Noob (merci à Google) à cette question - comme moi
Voici une solution récursive qui fonctionne sur un principe simple:

Set = {a, b, c, d, e} 
alors nous pouvons le casser en {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

     }
}

SORTIE

a
ab
abc
abcd
abd
ac
acd
ad
b
bc
bcd
bd
c
cd
d
8
NoobEditor

Il est clair que le nombre total de sous-ensembles d'un ensemble donné est égal à 2 ^ (nombre d'éléments dans l'ensemble). Si défini 

A = {1, 2, 3}

alors le sous-ensemble de A est:

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

Si nous regardons c'est comme des nombres binaires.

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

Si nous prenons en compte ci-dessus:

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);
    }
5
Zamir10

D'après ce que j'ai appris aujourd'hui, voici la solution JavaIl est basé sur 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;
    }
}

Son exécution donnera des résultats en tant que 

[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]
2
daydreamer
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
Shrikant Thakare

J'essayais en fait de résoudre celui-ci et j'ai obtenu l'algorithme @phimuemue dans le post précédent. Voici ce que j'ai implémenté. J'espère que ça marche.

/**
*@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);
        }

    }

}
1
Sherin Syriac
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;
}
1
A-patel-guy

Si vous traitez avec une vaste collection d'éléments, vous pouvez (bien que ce ne soit probablement pas le cas) rencontrer des problèmes de débordement de pile. J'admets que vous manquerez probablement de mémoire avant de surcharger la pile, mais je vais quand même mettre cette méthode non récursive ici.

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;
}

Ou si vous préférez traiter avec des tableaux:

@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;
}
1
Jeff Brower
// 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 } 
1
Vijay Inani

Voici un pseudocode. Vous pouvez couper les mêmes appels récursifs en stockant les valeurs de chaque appel au fur et à mesure et avant de vérifier les appels récursifs si la valeur de l'appel est déjà présente.

L'algorithme suivant aura tous les sous-ensembles à l'exclusion de l'ensemble vide.

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;
    }
}
0
kofhearts