web-dev-qa-db-fra.com

Algorithme pour générer toutes les combinaisons d'une chaîne

J'ai trouvé un lien en ligne qui montre un algorithme pour générer toutes les combinaisons d'une chaîne: http://www.mytechinterviews.com/combinations-of-a-string

L'algorithme est copié ci-dessous.

void combine(String instr, StringBuffer outstr, int index)
{
    for (int i = index; i < instr.length(); i++)
    {
        outstr.append(instr.charAt(i));
        System.out.println(outstr);
        combine(instr, outstr, i + 1);
        outstr.deleteCharAt(outstr.length() - 1);
    }
} 

combine("abc", new StringBuffer(), 0);

Ce que je ne comprends pas, c'est la ligne:

outstr.deleteCharAt(outstr.length() - 1);

Si je supprime cette ligne, le programme ne fonctionne évidemment plus, mais pourquoi est-ce nécessaire en premier lieu? Je comprends l’idée récursive selon laquelle nous modifions un caractère initial et répétons les caractères restants, mais la ligne deleteChar ne semble pas logiquement se loger nulle part. Quelle était la raison pour laquelle vous avez ajouté la ligne outstr.deleteCharAt?

14
john

L'appel de outstr.deleteCharAt neutralise l'effet de outstr.append en supprimant le dernier caractère de la outstr.

Chaque itération de boucle se déroule comme suit:

  1. ajouter un personnage
  2. imprimer le résultat
  3. effectuer une invocation récursive au niveau i+1
  4. supprimer le personnage que nous avons ajouté à l'étape 1
8
dasblinkenlight

Voici le moyen le plus simple de calculer les combinaisons possibles de chaînes.

Mathématiquement pour trouver R combinaisons dans un lot donné de N = NcR

Nous trouvons donc toutes les combinaisons possibles = Nc0 + Nc1 .... + Ncn = 2 Pow N

Vous obtenez donc 2 combinaisons Pow N pour un mot de longueur N caractères donné.

Si vous représentez 1 à (2 Pow N) entiers en binaire et placez votre caractère à l'endroit où 1 est présent, vous obtiendrez finalement la solution.

Exemple:

Entrée: ABC

Solution :

La longueur ABC est de 3. Donc combinaisons possibles 2 Pow 3 = 8

Si 0 - 8 représenté en binaire

000 = 

001 = C

010 = B

011 = BC

100 = A

101 = AC

110 = AB

111 = ABC

toutes les combinaisons possibles sont indiquées ci-dessus.

30
Sunil

Il équilibre la première ligne du corps de la boucle et restaure ce qu'il était en haut du corps de la boucle (en supprimant le caractère de l'instr ajouté). 

4
Scott Hunter

Le code ci-dessous sert à générer une permutation et une combinaison de chaînes. Le principe consiste à sélectionner un caractère à la fois:

public class permutecombo
{
  static void initiate(String s)
  {
    permute("", s);
    System.out.println("----------------------------------------- ");
    combo("", s);
    System.out.println("----------------------------------------- ");
  }

  static void combo(String prefix, String s)
  {
    int N = s.length();

    System.out.println(prefix);

    for (int i = 0 ; i < N ; i++)
      combo(prefix + s.charAt(i), s.substring(i+1));
  }
  static void permute(String prefix, String s)
  {
    int N = s.length();

    if (N == 0)
      System.out.println(" " + prefix);

    for (int i = 0 ; i < N ; i++)
      permute(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
  }

  public static void main(String[] args)
  {
    String s = "1234";
    initiate(s);
  }
}
3
nmd

Cela va très logiquement. Vous voyez que nous avons ici un algorithme récursif. À chaque étape de la position i, nous mettons une lettre de la chaîne, puis appelons la fonction de manière récursive pour placer une autre lettre à la position suivante. Cependant, lorsque nous revenons de récursion, nous devons supprimer le caractère que nous avons mis initialement afin de pouvoir le remplacer par le suivant possible dans la séquence. Exemple:

append a on pos 0 -> a
call recursion
append a on pos 1 -> aa
call recursion
append a on pos 2 -> aaa
return from recursion
remove a from pos 2 -> aa
append b on pos 2 -> aab
return from recursion
remove b from pos 2 -> aa
append c on pos 2 -> aac
etc.
3
Tudor

Nous pouvons générer toutes les sous-chaînes d'une chaîne en utilisant le concept de bit mentionné précédemment. Voici le code (en C++, mais vous avez l'idée) pour le faire: -

string s;
int n = s.size();
int num = 1<<n;
for(int i =1; i< num ; i++){ //Checks all the permutations.
    int value = i;
    int j, pos;
    for (j=1, pos=1; j < num; j<<=1, pos++) //Finds the bits that are set
        if (i & j)
            cout<<s[pos-1]; //You can print s[n-pos] to print according to bit position
    cout<<endl;        
}

Par exemple, - String s = abc

 The size is 3  . So we check from 1 to 7 ( 1<<3).
 for i = 1 ( 001 ) , the first bit is set, so a is printed.
 for i = 2 ( 010 ) , the second bit is set, so b is printed.
 for i = 3 ( 011 ) , the first and second bit are set, so ab is printed.
 .
 .
 .
 for i = 7 ( 111 ) , all three bits are set, so abc is printed.
1
user2125722
outstr.deleteCharAt(outstr.length() - 1); 

signifie que vous avez 

n^(n-1)/2 pairs of combinations.

La boucle for itérative ne s’arrête pas après l’appel de fonction récursif, vous devez donc supprimer le dernier caractère du tampon de sortie car vous ne voulez pas obtenir 

n^n/2 pairs of combinations.

Dans une théorie des graphes, ce serait un court-circuit. 

1
Bytemain

Voici du code C++ sans l'étape de retour en arrière délicate de la question de OP.

#include <iostream>
#include <string>
using namespace std;
static const string in("abc");
void combine(int i, string out)
{
    if (i==in.size()) {
        cout << out << endl;
        return;
    }
    combine(i+1, out);
    combine(i+1, out+in[i]);
}

int main()
{
    combine(0, "");
    return 0;
}

J'espère que cela capture mieux l'esprit des combinaisons.

1
Hackless
// IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!

import Java.util.*;
public class Permutation {

    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        System.out.println("ENTER A STRING");
        Set<String> se=find(in.nextLine());
        System.out.println((se));
    }
    public static Set<String> find(String s)
    {
        Set<String> ss=new HashSet<String>();
        if(s==null)
        {
            return null;
        }
        if(s.length()==0)
        {
            ss.add("");
        }
        else
        {
            char c=s.charAt(0);
            String st=s.substring(1);
            Set<String> qq=find(st);
            for(String str:qq)
            {
                for(int i=0;i<=str.length();i++)
                {
                    ss.add(comb(str,c,i));
                }
            }
        }
        return ss;

    }
    public static String comb(String s,char c,int i)
    {
        String start=s.substring(0,i);
        String end=s.substring(i);
        return start+c+end;
    }

}


// IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!
0