Génération de toutes les permutations d'une chaîne donnée

418

Quelle est une manière élégante de trouver toutes les permutations d'une chaîne. Par exemple, la permutation pour ba, serait baet ab, mais qu'en est-il de la chaîne plus longue comme abcdefgh? Existe-t-il un exemple d'implémentation Java?

GurdeepS
la source
3
Il y a beaucoup de réponses ici: stackoverflow.com/questions/361/…
Marek Sapota
c'est une question très populaire. vous pouvez jeter un oeil ici: careercup.com/question?id=3861299
JJunior
9
Il y a une hypothèse à mentionner. Les personnages sont uniques. Par exemple, pour une chaîne "aaaa", il n'y a qu'une seule réponse. Pour avoir une réponse plus générale, vous pouvez enregistrer les chaînes dans un ensemble pour éviter la duplication
Afshin Moazami
1
La répétition des caractères est-elle autorisée ou la répétition des caractères n'est-elle pas autorisée? Une même chaîne peut-elle avoir plusieurs occurrences du même caractère?
Anderson Green
2
Lisez la théorie (ou si, comme moi, vous êtes paresseux, allez sur en.wikipedia.org/wiki/Permutation ) et implémentez un véritable algorithme. Fondamentalement, vous pouvez générer une séquence d'ordonnances d'éléments (le fait que ce soit une chaîne n'est pas pertinent) et parcourir les ordres jusqu'à ce que vous reveniez au début. Évitez tout ce qui implique une récursivité ou des manipulations de chaînes.
CurtainDog

Réponses:

601
public static void permutation(String str) { 
    permutation("", str); 
}

private static void permutation(String prefix, String str) {
    int n = str.length();
    if (n == 0) System.out.println(prefix);
    else {
        for (int i = 0; i < n; i++)
            permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
    }
}

(via Introduction à la programmation en Java )

SuperJulietta
la source
67
La solution semble venir d'ici introcs.cs.princeton.edu/java/23recursion/…
cyber-moine
48
Ce n'est pas sorcier, j'ai trouvé à peu près la même réponse. Petit ajustement: au lieu de répéter jusqu'à n==0, vous pouvez arrêter un niveau plus tôt n==1et imprimer prefix + str.
lambshaanxy
7
"Quelle est la complexité temporelle et spatiale de cela?" sans une sorte de réponse partielle, la mise en cache de tout algorithme qui génère une permutation est o (n!) car le jeu de résultats à la question de permutation est factoriel à l'entrée.
jeremyjjbrown
9
Élégant, oui. Mais une solution qui se convertit en un tableau de caractères et échange pour générer les permutations nécessitera beaucoup moins de copie et générera beaucoup moins de déchets. De plus, cet algorithme ne prend pas en compte les caractères répétés.
Gene
20
@AfshinMoazami Je pense que str.substring (i + 1, n) peut être remplacé par str.substring (i + 1). L'utilisation de str.substring (i) provoquera java.lang.StackOverflowError.
Ayusman
196

Utilisez la récursivité.

  • Essayez chacune des lettres tour à tour comme première lettre, puis recherchez toutes les permutations des lettres restantes à l'aide d'un appel récursif.
  • Le cas de base est lorsque l'entrée est une chaîne vide, la seule permutation est la chaîne vide.
Mark Byers
la source
3
Comment pouvez-vous ajouter un type de retour à la méthode permute? le compilateur ne peut pas déterminer le type de retour de cette méthode à chaque itération, même s'il s'agit évidemment d'un type String.
user1712095
Comment garantissez-vous des permutations distinctes dans cette méthode?
kapad
70

Voici ma solution qui est basée sur l'idée du livre "Cracking the Coding Interview" (P54):

/**
 * List permutations of a string.
 * 
 * @param s the input string
 * @return  the list of permutations
 */
public static ArrayList<String> permutation(String s) {
    // The result
    ArrayList<String> res = new ArrayList<String>();
    // If input string's length is 1, return {s}
    if (s.length() == 1) {
        res.add(s);
    } else if (s.length() > 1) {
        int lastIndex = s.length() - 1;
        // Find out the last character
        String last = s.substring(lastIndex);
        // Rest of the string
        String rest = s.substring(0, lastIndex);
        // Perform permutation on the rest string and
        // merge with the last character
        res = merge(permutation(rest), last);
    }
    return res;
}

/**
 * @param list a result of permutation, e.g. {"ab", "ba"}
 * @param c    the last character
 * @return     a merged new list, e.g. {"cab", "acb" ... }
 */
public static ArrayList<String> merge(ArrayList<String> list, String c) {
    ArrayList<String> res = new ArrayList<>();
    // Loop through all the string in the list
    for (String s : list) {
        // For each string, insert the last character to all possible positions
        // and add them to the new list
        for (int i = 0; i <= s.length(); ++i) {
            String ps = new StringBuffer(s).insert(i, c).toString();
            res.add(ps);
        }
    }
    return res;
}

Exécution de la sortie de la chaîne "abcd":

  • Étape 1: fusionnez [a] et b: [ba, ab]

  • Étape 2: fusionnez [ba, ab] et c: [cba, bca, bac, cab, acb, abc]

  • Étape 3: fusionner [cba, bca, bac, cab, acb, abc] et d: [dcba, cdba, cbda, cbad, dbca, bdca, bcda, bcad, dbac, bdac, badc, bacd, dcab, cdab, cadb , cabd, dacb, adcb, acdb, acbd, dabc, adbc, abdc, abcd]

jeantimex
la source
Page (71) dans Cracking the Coding Interview Book, 6e édition. :)
KarimIhab
5
Est-ce vraiment une bonne solution? Il repose sur le stockage des résultats dans une liste, donc pour une courte chaîne d'entrée, il devient hors de contrôle.
Androrider
que fait la fusion?
Basavaraj Walikar
Il insère c dans toutes les positions possibles de chaque chaîne de la liste, donc si list ne contient que ["b"] et c est "a" le résultat de la fusion est ["ab", "ba"] ici même solution avec Swift gist.github. com / daniaDlbani / 3bc10e02541f9ba310d546040c5322fc
Dania Delbani
53

De toutes les solutions proposées ici et dans d'autres forums, j'ai le plus apprécié Mark Byers. Cette description m'a en fait fait réfléchir et coder moi-même. Dommage que je ne puisse pas voter contre sa solution car je suis novice.
Quoi qu'il en soit, voici ma mise en œuvre de sa description

public class PermTest {

    public static void main(String[] args) throws Exception {
        String str = "abcdef";
        StringBuffer strBuf = new StringBuffer(str);
        doPerm(strBuf,0);
    }

    private static void doPerm(StringBuffer str, int index){

        if(index == str.length())
            System.out.println(str);            
        else { //recursively solve this by placing all other chars at current first pos
            doPerm(str, index+1);
            for (int i = index+1; i < str.length(); i++) {//start swapping all other chars with current first char
                swap(str,index, i);
                doPerm(str, index+1);
                swap(str,i, index);//restore back my string buffer
            }
        }
    }

    private  static void swap(StringBuffer str, int pos1, int pos2){
        char t1 = str.charAt(pos1);
        str.setCharAt(pos1, str.charAt(pos2));
        str.setCharAt(pos2, t1);
    }
}   

Je préfère cette solution avant la première dans ce fil parce que cette solution utilise StringBuffer. Je ne dirais pas que ma solution ne crée aucune chaîne temporaire (elle le fait en fait à l' system.out.printlnendroit où le toString()StringBuffer est appelé). Mais je pense que c'est mieux que la première solution où trop de littéraux de chaînes sont créés. Peut-être qu'un gars de la performance peut évaluer cela en termes de `` mémoire '' (pour le `` temps '', il est déjà en retard en raison de ce `` swap '' supplémentaire)

srikanth yaradla
la source
Pourquoi ne pas simplement faire if(index == str.length())et doPerm(str, index + 1);? Le currPossemble inutile ici.
Robur_131
Désolé, pouvez-vous nous en dire plus sur la question? Suggérez-vous simplement de ne pas utiliser de currPos variables supplémentaires (utilisées en raison de plusieurs occurrences et également de la lisibilité) sinon, collez la solution que vous proposez de jeter un coup d'œil
srikanth yaradla
Ah je comprends que vous vouliez dire le changement à la condition de base avec l'indexation directe. Fonctionne bien. Juste que la solution que j'ai présentée était principalement influencée par les autres solutions qui passaient souvent la chaîne tronquée plutôt que l'original (ce qui est le cas 0). Néanmoins merci d'avoir pointé. Va voir si je peux éditer, ça fait des années que je ne me suis pas connecté à ce site.
srikanth yaradla
22

Une solution très basique en Java consiste à utiliser récursivité + Set (pour éviter les répétitions) si vous souhaitez stocker et renvoyer les chaînes de solution:

public static Set<String> generatePerm(String input)
{
    Set<String> set = new HashSet<String>();
    if (input == "")
        return set;

    Character a = input.charAt(0);

    if (input.length() > 1)
    {
        input = input.substring(1);

        Set<String> permSet = generatePerm(input);

        for (String x : permSet)
        {
            for (int i = 0; i <= x.length(); i++)
            {
                set.add(x.substring(0, i) + a + x.substring(i));
            }
        }
    }
    else
    {
        set.add(a + "");
    }
    return set;
}
dévastateur
la source
2
Quelle est la complexité temporelle de cet alogrithme ??
ashisahu
1
@ashisahu O (n!) puisque nous avons n! permutations dans une chaîne donnée de longueur n.
Zok
17

Tous les contributeurs précédents ont fait un excellent travail en expliquant et en fournissant le code. J'ai pensé que je devrais aussi partager cette approche car cela pourrait aider quelqu'un aussi. La solution est basée sur ( algorithme de tas )

Quelques choses:

  1. Remarquez que le dernier élément décrit dans Excel est juste pour vous aider à mieux visualiser la logique. Ainsi, les valeurs réelles dans la dernière colonne seraient 2,1,0 (si nous devions exécuter le code car nous avons affaire à des tableaux et les tableaux commencent par 0).

  2. L'algorithme de permutation se produit en fonction des valeurs paires ou impaires de la position actuelle. Il est très explicite si vous regardez où la méthode de swap est appelée. Vous pouvez voir ce qui se passe.

Voici ce qui se passe: entrez la description de l'image ici

public static void main(String[] args) {

        String ourword = "abc";
        String[] ourArray = ourword.split("");
        permute(ourArray, ourArray.length);

    }

    private static void swap(String[] ourarray, int right, int left) {
        String temp = ourarray[right];
        ourarray[right] = ourarray[left];
        ourarray[left] = temp;
    }

    public static void permute(String[] ourArray, int currentPosition) {
        if (currentPosition == 1) {
            System.out.println(Arrays.toString(ourArray));
        } else {
            for (int i = 0; i < currentPosition; i++) {
                // subtract one from the last position (here is where you are
                // selecting the the next last item 
                permute(ourArray, currentPosition - 1);

                // if it's odd position
                if (currentPosition % 2 == 1) {
                    swap(ourArray, 0, currentPosition - 1);
                } else {
                    swap(ourArray, i, currentPosition - 1);
                }
            }
        }
    }
grepit
la source
11

Celui-ci est sans récursivité

public static void permute(String s) {
    if(null==s || s.isEmpty()) {
        return;
    }

    // List containing words formed in each iteration 
    List<String> strings = new LinkedList<String>();
    strings.add(String.valueOf(s.charAt(0))); // add the first element to the list

     // Temp list that holds the set of strings for 
     //  appending the current character to all position in each word in the original list
    List<String> tempList = new LinkedList<String>(); 

    for(int i=1; i< s.length(); i++) {

        for(int j=0; j<strings.size(); j++) {
            tempList.addAll(merge(s.charAt(i), strings.get(j)));
                        }
        strings.removeAll(strings);
        strings.addAll(tempList);

        tempList.removeAll(tempList);

    }

    for(int i=0; i<strings.size(); i++) {
        System.out.println(strings.get(i));
    }
}

/**
 * helper method that appends the given character at each position in the given string 
 * and returns a set of such modified strings 
 * - set removes duplicates if any(in case a character is repeated)
 */
private static Set<String> merge(Character c,  String s) {
    if(s==null || s.isEmpty()) {
        return null;
    }

    int len = s.length();
    StringBuilder sb = new StringBuilder();
    Set<String> list = new HashSet<String>();

    for(int i=0; i<= len; i++) {
        sb = new StringBuilder();
        sb.append(s.substring(0, i) + c + s.substring(i, len));
        list.add(sb.toString());
    }

    return list;
}
Jeya
la source
cette solution semble erronée System.out.println(permute("AABBC").size());affiche 45, mais en fait 5! = 120
Mladen Adamovic
11

Utilisons l'entrée abc comme exemple.

Commencez avec juste le dernier élément ( c) dans un ensemble ( ["c"]), puis ajoutez l'avant-dernier élément ( b) à son avant, à son extrémité et à toutes les positions possibles au milieu, ce qui en fait ["bc", "cb"], puis de la même manière, il ajoutera l'élément suivant de l'arrière ( a) à chaque chaîne de l'ensemble, ce qui en fait:

"a" + "bc" = ["abc", "bac", "bca"]  and  "a" + "cb" = ["acb" ,"cab", "cba"] 

Ainsi toute permutation:

["abc", "bac", "bca","acb" ,"cab", "cba"]

Code:

public class Test 
{
    static Set<String> permutations;
    static Set<String> result = new HashSet<String>();

    public static Set<String> permutation(String string) {
        permutations = new HashSet<String>();

        int n = string.length();
        for (int i = n - 1; i >= 0; i--) 
        {
            shuffle(string.charAt(i));
        }
        return permutations;
    }

    private static void shuffle(char c) {
        if (permutations.size() == 0) {
            permutations.add(String.valueOf(c));
        } else {
            Iterator<String> it = permutations.iterator();
            for (int i = 0; i < permutations.size(); i++) {

                String temp1;
                for (; it.hasNext();) {
                    temp1 = it.next();
                    for (int k = 0; k < temp1.length() + 1; k += 1) {
                        StringBuilder sb = new StringBuilder(temp1);

                        sb.insert(k, c);

                        result.add(sb.toString());
                    }
                }
            }
            permutations = result;
            //'result' has to be refreshed so that in next run it doesn't contain stale values.
            result = new HashSet<String>();
        }
    }

    public static void main(String[] args) {
        Set<String> result = permutation("abc");

        System.out.println("\nThere are total of " + result.size() + " permutations:");
        Iterator<String> it = result.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}
Vihaan Verma
la source
1
J'ai adoré ta solution. Très intuitif et bien expliqué. Merci beaucoup.
user2585781
9

Eh bien voici une solution O (n!) Élégante et non récursive:

public static StringBuilder[] permutations(String s) {
        if (s.length() == 0)
            return null;
        int length = fact(s.length());
        StringBuilder[] sb = new StringBuilder[length];
        for (int i = 0; i < length; i++) {
            sb[i] = new StringBuilder();
        }
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            int times = length / (i + 1);
            for (int j = 0; j < times; j++) {
                for (int k = 0; k < length / times; k++) {
                    sb[j * length / times + k].insert(k, ch);
                }
            }
        }
        return sb;
    }
Adilli Adil
la source
Cette solution ne fonctionne que si le mot a moins de 4 lettres, sinon seulement la moitié du tableau résultant contient des mots uniques.
Maksim Maksimov
5

L'une des solutions les plus simples pourrait être de continuer à échanger les caractères récursivement à l'aide de deux pointeurs.

public static void main(String[] args)
{
    String str="abcdefgh";
    perm(str);
}
public static void perm(String str)
{  char[] char_arr=str.toCharArray();
    helper(char_arr,0);
}
public static void helper(char[] char_arr, int i)
{
    if(i==char_arr.length-1)
    {
        // print the shuffled string 
            String str="";
            for(int j=0; j<char_arr.length; j++)
            {
                str=str+char_arr[j];
            }
            System.out.println(str);
    }
    else
    {
    for(int j=i; j<char_arr.length; j++)
    {
        char tmp = char_arr[i];
        char_arr[i] = char_arr[j];
        char_arr[j] = tmp;
        helper(char_arr,i+1);
        char tmp1 = char_arr[i];
        char_arr[i] = char_arr[j];
        char_arr[j] = tmp1;
    }
}
}
Katie
la source
Ceci est similaire à la solution donnée ici: geeksforgeeks.org/… , impliquant un retour en arrière et une complexité temporelle O (n * n!).
Nakul Kumar
5

implémentation de python

def getPermutation(s, prefix=''):
        if len(s) == 0:
                print prefix
        for i in range(len(s)):
                getPermutation(s[0:i]+s[i+1:len(s)],prefix+s[i] )



getPermutation('abcd','')
riteshkasat
la source
4

cela a fonctionné pour moi ..

import java.util.Arrays;

public class StringPermutations{
    public static void main(String args[]) {
        String inputString = "ABC";
        permute(inputString.toCharArray(), 0, inputString.length()-1);
    }

    public static void permute(char[] ary, int startIndex, int endIndex) {
        if(startIndex == endIndex){
            System.out.println(String.valueOf(ary));
        }else{
            for(int i=startIndex;i<=endIndex;i++) {
                 swap(ary, startIndex, i );
                 permute(ary, startIndex+1, endIndex);
                 swap(ary, startIndex, i );
            }
        }
    }

    public static void swap(char[] ary, int x, int y) {
        char temp = ary[x];
        ary[x] = ary[y];
        ary[y] = temp;
    }
}
Arun Kumar Mudraboyina
la source
3

Utilisez la récursivité.

lorsque l'entrée est une chaîne vide, la seule permutation est une chaîne vide.Essayez pour chacune des lettres de la chaîne en la créant comme première lettre, puis recherchez toutes les permutations des lettres restantes à l'aide d'un appel récursif.

import java.util.ArrayList;
import java.util.List;

class Permutation {
    private static List<String> permutation(String prefix, String str) {
        List<String> permutations = new ArrayList<>();
        int n = str.length();
        if (n == 0) {
            permutations.add(prefix);
        } else {
            for (int i = 0; i < n; i++) {
                permutations.addAll(permutation(prefix + str.charAt(i), str.substring(i + 1, n) + str.substring(0, i)));
            }
        }
        return permutations;
    }

    public static void main(String[] args) {
        List<String> perms = permutation("", "abcd");

        String[] array = new String[perms.size()];
        for (int i = 0; i < perms.size(); i++) {
            array[i] = perms.get(i);
        }

        int x = array.length;

        for (final String anArray : array) {
            System.out.println(anArray);
        }
    }
}
coder101
la source
3

Permettez-moi d'essayer de résoudre ce problème avec Kotlin:

fun <T> List<T>.permutations(): List<List<T>> {
    //escape case
    if (this.isEmpty()) return emptyList()

    if (this.size == 1) return listOf(this)

    if (this.size == 2) return listOf(listOf(this.first(), this.last()), listOf(this.last(), this.first()))

    //recursive case
    return this.flatMap { lastItem ->
        this.minus(lastItem).permutations().map { it.plus(lastItem) }
    }
}

Concept de base: décomposer la longue liste en une liste plus petite + récursivité

Réponse longue avec liste d'exemples [1, 2, 3, 4]:

Même pour une liste de 4, il est déjà un peu déroutant d'essayer de répertorier toutes les permutations possibles dans votre tête, et ce que nous devons faire est exactement d'éviter cela. Il est facile pour nous de comprendre comment faire toutes les permutations de la liste des tailles 0, 1 et 2, donc tout ce que nous devons faire est de les décomposer en l'une de ces tailles et de les combiner correctement. Imaginez une machine à jackpot: cet algorithme commencera à tourner de la droite vers la gauche et notera

  1. renvoie vide / liste de 1 lorsque la taille de la liste est 0 ou 1
  2. gérer lorsque la taille de la liste est 2 (par exemple [3, 4]), et générer les 2 permutations ([3, 4] & [4, 3])
  3. Pour chaque élément, marquez-le comme le dernier dans le dernier et recherchez toutes les permutations pour le reste de l'élément dans la liste. (par exemple, mettez [4] sur la table et jetez à nouveau [1, 2, 3] en permutation)
  4. Maintenant, avec toute permutation, ce sont des enfants, remettez-vous à la fin de la liste (par exemple: [1, 2, 3] [, 4], [1, 3, 2] [, 4], [2, 3, 1] [, 4], ...)
Louis Tsai
la source
2
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class hello {
    public static void main(String[] args) throws IOException {
        hello h = new hello();
        h.printcomp();
    }
      int fact=1;
    public void factrec(int a,int k){
        if(a>=k)
        {fact=fact*k;
        k++;
        factrec(a,k);
        }
        else
        {System.out.println("The string  will have "+fact+" permutations");
        }
        }
    public void printcomp(){
        String str;
        int k;
        Scanner in = new Scanner(System.in);
        System.out.println("enter the string whose permutations has to b found");
        str=in.next();
        k=str.length();
        factrec(k,1);
        String[] arr =new String[fact];
        char[] array = str.toCharArray();
        while(p<fact)
        printcomprec(k,array,arr);
            // if incase u need array containing all the permutation use this
            //for(int d=0;d<fact;d++)         
        //System.out.println(arr[d]);
    }
    int y=1;
    int p = 0;
    int g=1;
    int z = 0;
    public void printcomprec(int k,char array[],String arr[]){
        for (int l = 0; l < k; l++) {
            for (int b=0;b<k-1;b++){
            for (int i=1; i<k-g; i++) {
                char temp;
                String stri = "";
                temp = array[i];
                array[i] = array[i + g];
                array[i + g] = temp;
                for (int j = 0; j < k; j++)
                    stri += array[j];
                arr[z] = stri;
                System.out.println(arr[z] + "   " + p++);
                z++;
            }
            }
            char temp;
            temp=array[0];
            array[0]=array[y];
            array[y]=temp;
            if (y >= k-1)
                y=y-(k-1);
            else
                y++;
        }
        if (g >= k-1)
            g=1;
        else
            g++;
    }

}
Antony Johnson
la source
2
/** Returns an array list containing all
 * permutations of the characters in s. */
public static ArrayList<String> permute(String s) {
    ArrayList<String> perms = new ArrayList<>();
    int slen = s.length();
    if (slen > 0) {
        // Add the first character from s to the perms array list.
        perms.add(Character.toString(s.charAt(0)));

        // Repeat for all additional characters in s.
        for (int i = 1;  i < slen;  ++i) {

            // Get the next character from s.
            char c = s.charAt(i);

            // For each of the strings currently in perms do the following:
            int size = perms.size();
            for (int j = 0;  j < size;  ++j) {

                // 1. remove the string
                String p = perms.remove(0);
                int plen = p.length();

                // 2. Add plen + 1 new strings to perms.  Each new string
                //    consists of the removed string with the character c
                //    inserted into it at a unique location.
                for (int k = 0;  k <= plen;  ++k) {
                    perms.add(p.substring(0, k) + c + p.substring(k));
                }
            }
        }
    }
    return perms;
}
Barzee
la source
2

Voici une solution récursive minimaliste simple en Java:

public static ArrayList<String> permutations(String s) {
    ArrayList<String> out = new ArrayList<String>();
    if (s.length() == 1) {
        out.add(s);
        return out;
    }
    char first = s.charAt(0);
    String rest = s.substring(1);
    for (String permutation : permutations(rest)) {
        out.addAll(insertAtAllPositions(first, permutation));
    }
    return out;
}
public static ArrayList<String> insertAtAllPositions(char ch, String s) {
    ArrayList<String> out = new ArrayList<String>();
    for (int i = 0; i <= s.length(); ++i) {
        String inserted = s.substring(0, i) + ch + s.substring(i);
        out.add(inserted);
    }
    return out;
}
Jay Taylor
la source
2

Nous pouvons utiliser factorielle pour trouver le nombre de chaînes commençant par une lettre particulière.

Exemple: prenez l'entrée abcd. (3!) == 6les chaînes commenceront par chaque lettre de abcd.

static public int facts(int x){
    int sum = 1;
    for (int i = 1; i < x; i++) {
        sum *= (i+1);
    }
    return sum;
}

public static void permutation(String str) {
    char[] str2 = str.toCharArray();
    int n = str2.length;
    int permutation = 0;
    if (n == 1) {
        System.out.println(str2[0]);
    } else if (n == 2) {
        System.out.println(str2[0] + "" + str2[1]);
        System.out.println(str2[1] + "" + str2[0]);
    } else {
        for (int i = 0; i < n; i++) {
            if (true) {
                char[] str3 = str.toCharArray();
                char temp = str3[i];
                str3[i] = str3[0];
                str3[0] = temp;
                str2 = str3;
            }

            for (int j = 1, count = 0; count < facts(n-1); j++, count++) {
                if (j != n-1) {
                    char temp1 = str2[j+1];
                    str2[j+1] = str2[j];
                    str2[j] = temp1;
                } else {
                    char temp1 = str2[n-1];
                    str2[n-1] = str2[1];
                    str2[1] = temp1;
                    j = 1;
                } // end of else block
                permutation++;
                System.out.print("permutation " + permutation + " is   -> ");
                for (int k = 0; k < n; k++) {
                    System.out.print(str2[k]);
                } // end of loop k
                System.out.println();
            } // end of loop j
        } // end of loop i
    }
}
user1685821
la source
2

C'est ce que j'ai fait grâce à une compréhension de base des permutations et des appels de fonction récursifs. Prend un peu de temps mais cela se fait de façon indépendante.

public class LexicographicPermutations {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    String s="abc";
    List<String>combinations=new ArrayList<String>();
    combinations=permutations(s);
    Collections.sort(combinations);
    System.out.println(combinations);
}

private static List<String> permutations(String s) {
    // TODO Auto-generated method stub
    List<String>combinations=new ArrayList<String>();
    if(s.length()==1){
        combinations.add(s);
    }
    else{
        for(int i=0;i<s.length();i++){
            List<String>temp=permutations(s.substring(0, i)+s.substring(i+1));
            for (String string : temp) {
                combinations.add(s.charAt(i)+string);
            }
        }
    }
    return combinations;
}}

qui génère une sortie en tant que[abc, acb, bac, bca, cab, cba] .

La logique de base derrière elle est

Pour chaque personnage, considérez-le comme le 1er personnage et trouvez les combinaisons des caractères restants. par exemple [abc](Combination of abc)->.

  1. a->[bc](a x Combination of (bc))->{abc,acb}
  2. b->[ac](b x Combination of (ac))->{bac,bca}
  3. c->[ab](c x Combination of (ab))->{cab,cba}

Et puis récursivement en appelant chacun [bc], [ac]et [ab]indépendamment.

Shabbir Essaji
la source
2

Implémentation Java sans récursivité

public Set<String> permutate(String s){
    Queue<String> permutations = new LinkedList<String>();
    Set<String> v = new HashSet<String>();
    permutations.add(s);

    while(permutations.size()!=0){
        String str = permutations.poll();
        if(!v.contains(str)){
            v.add(str);
            for(int i = 0;i<str.length();i++){
                String c = String.valueOf(str.charAt(i));
                permutations.add(str.substring(i+1) + c +  str.substring(0,i));
            }
        }
    }
    return v;
}
Hadi Elmougy
la source
1

// insère chaque caractère dans une liste de tableaux

static ArrayList al = new ArrayList();

private static void findPermutation (String str){
    for (int k = 0; k < str.length(); k++) {
        addOneChar(str.charAt(k));
    }
}

//insert one char into ArrayList
private static void addOneChar(char ch){
    String lastPerStr;
    String tempStr;
    ArrayList locAl = new ArrayList();
    for (int i = 0; i < al.size(); i ++ ){
        lastPerStr = al.get(i).toString();
        //System.out.println("lastPerStr: " + lastPerStr);
        for (int j = 0; j <= lastPerStr.length(); j++) {
            tempStr = lastPerStr.substring(0,j) + ch + 
                    lastPerStr.substring(j, lastPerStr.length());
            locAl.add(tempStr);
            //System.out.println("tempStr: " + tempStr);
        }
    }
    if(al.isEmpty()){
        al.add(ch);
    } else {
        al.clear();
        al = locAl;
    }
}

private static void printArrayList(ArrayList al){
    for (int i = 0; i < al.size(); i++) {
        System.out.print(al.get(i) + "  ");
    }
}
David Lee
la source
Je ne trouve pas cette réponse utile , car elle ne contient aucune explication et il utilise le même algorithme que quelques autres réponses qui font fournir une explication.
Bernhard Barker
1
//Rotate and create words beginning with all letter possible and push to stack 1

//Read from stack1 and for each word create words with other letters at the next location by rotation and so on 

/*  eg : man

    1. push1 - man, anm, nma
    2. pop1 - nma ,  push2 - nam,nma
       pop1 - anm ,  push2 - amn,anm
       pop1 - man ,  push2 - mna,man
*/

public class StringPermute {

    static String str;
    static String word;
    static int top1 = -1;
    static int top2 = -1;
    static String[] stringArray1;
    static String[] stringArray2;
    static int strlength = 0;

    public static void main(String[] args) throws IOException {
        System.out.println("Enter String : ");
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader bfr = new BufferedReader(isr);
        str = bfr.readLine();
        word = str;
        strlength = str.length();
        int n = 1;
        for (int i = 1; i <= strlength; i++) {
            n = n * i;
        }
        stringArray1 = new String[n];
        stringArray2 = new String[n];
        push(word, 1);
        doPermute();
        display();
    }

    public static void push(String word, int x) {
        if (x == 1)
            stringArray1[++top1] = word;
        else
            stringArray2[++top2] = word;
    }

    public static String pop(int x) {
        if (x == 1)
            return stringArray1[top1--];
        else
            return stringArray2[top2--];
    }

    public static void doPermute() {

        for (int j = strlength; j >= 2; j--)
            popper(j);

    }

    public static void popper(int length) {
        // pop from stack1 , rotate each word n times and push to stack 2
        if (top1 > -1) {
            while (top1 > -1) {
                word = pop(1);
                for (int j = 0; j < length; j++) {
                    rotate(length);
                    push(word, 2);
                }
            }
        }
        // pop from stack2 , rotate each word n times w.r.t position and push to
        // stack 1
        else {
            while (top2 > -1) {
                word = pop(2);
                for (int j = 0; j < length; j++) {
                    rotate(length);
                    push(word, 1);
                }
            }
        }

    }

    public static void rotate(int position) {
        char[] charstring = new char[100];
        for (int j = 0; j < word.length(); j++)
            charstring[j] = word.charAt(j);

        int startpos = strlength - position;
        char temp = charstring[startpos];
        for (int i = startpos; i < strlength - 1; i++) {
            charstring[i] = charstring[i + 1];
        }
        charstring[strlength - 1] = temp;
        word = new String(charstring).trim();
    }

    public static void display() {
        int top;
        if (top1 > -1) {
            while (top1 > -1)
                System.out.println(stringArray1[top1--]);
        } else {
            while (top2 > -1)
                System.out.println(stringArray2[top2--]);
        }
    }
}
nnc
la source
1

Une autre façon simple est de parcourir la chaîne, de choisir le caractère qui n'est pas encore utilisé et de le mettre dans un tampon, de continuer la boucle jusqu'à ce que la taille du tampon soit égale à la longueur de la chaîne. J'aime mieux cette solution de suivi arrière car:

  1. Facile à comprendre
  2. Facile à éviter la duplication
  3. La sortie est triée

Voici le code java:

List<String> permute(String str) {
  if (str == null) {
    return null;
  }

  char[] chars = str.toCharArray();
  boolean[] used = new boolean[chars.length];

  List<String> res = new ArrayList<String>();
  StringBuilder sb = new StringBuilder();

  Arrays.sort(chars);

  helper(chars, used, sb, res);

  return res;
}

void helper(char[] chars, boolean[] used, StringBuilder sb, List<String> res) {
  if (sb.length() == chars.length) {
    res.add(sb.toString());
    return;
  }

  for (int i = 0; i < chars.length; i++) {
    // avoid duplicates
    if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
      continue;
    }

    // pick the character that has not used yet
    if (!used[i]) {
      used[i] = true;
      sb.append(chars[i]);

      helper(chars, used, sb, res);

      // back tracking
      sb.deleteCharAt(sb.length() - 1);
      used[i] = false;
    }
  }
}

Chaîne d'entrée: 1231

Liste de sortie: {1123, 1132, 1213, 1231, 1312, 1321, 2113, 2131, 2311, 3112, 3121, 3211}

Remarqué que la sortie est triée et qu'il n'y a pas de résultat en double.

jeantimex
la source
1

Récursivité n'est pas nécessaire, même si vous pouvez calculer directement n'importe quelle permutation , cette solution utilise des génériques pour permuter n'importe quel tableau.

Voici une bonne information sur cet algorithme.

Pour les développeurs C # voici une implémentation plus utile.

public static void main(String[] args) {
    String word = "12345";

    Character[] array = ArrayUtils.toObject(word.toCharArray());
    long[] factorials = Permutation.getFactorials(array.length + 1);

    for (long i = 0; i < factorials[array.length]; i++) {
        Character[] permutation = Permutation.<Character>getPermutation(i, array, factorials);
        printPermutation(permutation);
    }
}

private static void printPermutation(Character[] permutation) {
    for (int i = 0; i < permutation.length; i++) {
        System.out.print(permutation[i]);
    }
    System.out.println();
}

Cet algorithme a O (N) complexité temporelle et spatiale pour calculer chaque permutation .

public class Permutation {
    public static <T> T[] getPermutation(long permutationNumber, T[] array, long[] factorials) {
        int[] sequence = generateSequence(permutationNumber, array.length - 1, factorials);
        T[] permutation = generatePermutation(array, sequence);

        return permutation;
    }

    public static <T> T[] generatePermutation(T[] array, int[] sequence) {
        T[] clone = array.clone();

        for (int i = 0; i < clone.length - 1; i++) {
            swap(clone, i, i + sequence[i]);
        }

        return clone;
    }

    private static int[] generateSequence(long permutationNumber, int size, long[] factorials) {
        int[] sequence = new int[size];

        for (int j = 0; j < sequence.length; j++) {
            long factorial = factorials[sequence.length - j];
            sequence[j] = (int) (permutationNumber / factorial);
            permutationNumber = (int) (permutationNumber % factorial);
        }

        return sequence;
    }

    private static <T> void swap(T[] array, int i, int j) {
        T t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

    public static long[] getFactorials(int length) {
        long[] factorials = new long[length];
        long factor = 1;

        for (int i = 0; i < length; i++) {
            factor *= i <= 1 ? 1 : i;
            factorials[i] = factor;
        }

        return factorials;
    }
}
Najera
la source
1

Permutation de chaîne:

public static void main(String args[]) {
    permu(0,"ABCD");
}

static void permu(int fixed,String s) {
    char[] chr=s.toCharArray();
    if(fixed==s.length())
        System.out.println(s);
    for(int i=fixed;i<s.length();i++) {
        char c=chr[i];
        chr[i]=chr[fixed];
        chr[fixed]=c;
        permu(fixed+1,new String(chr));
    }   
}
sakivns
la source
1

Voici une autre méthode plus simple de permutation d'une chaîne.

public class Solution4 {
public static void main(String[] args) {
    String  a = "Protijayi";
  per(a, 0);

}

static void per(String a  , int start ) {
      //bse case;
    if(a.length() == start) {System.out.println(a);}
    char[] ca = a.toCharArray();
    //swap 
    for (int i = start; i < ca.length; i++) {
        char t = ca[i];
        ca[i] = ca[start];
        ca[start] = t;
        per(new String(ca),start+1);
    }

}//per

}
Soudipta Dutta
la source
1

Une implémentation Java pour imprimer toutes les permutations d'une chaîne donnée en tenant compte des caractères en double et imprime uniquement des caractères uniques est la suivante:

import java.util.Set;
import java.util.HashSet;

public class PrintAllPermutations2
{
    public static void main(String[] args)
    {
        String str = "AAC";

    PrintAllPermutations2 permutation = new PrintAllPermutations2();

    Set<String> uniqueStrings = new HashSet<>();

    permutation.permute("", str, uniqueStrings);
}

void permute(String prefixString, String s, Set<String> set)
{
    int n = s.length();

    if(n == 0)
    {
        if(!set.contains(prefixString))
        {
            System.out.println(prefixString);
            set.add(prefixString);
        }
    }
    else
    {
        for(int i=0; i<n; i++)
        {
            permute(prefixString + s.charAt(i), s.substring(0,i) + s.substring(i+1,n), set);
        }
    }
}
}
Paul92
la source
0
/*
     * eg: abc =>{a,bc},{b,ac},{c,ab}
     * =>{ca,b},{cb,a}
     * =>cba,cab
     * =>{ba,c},{bc,a}
     * =>bca,bac
     * =>{ab,c},{ac,b}
     * =>acb,abc
     */
    public void nonRecpermute(String prefix, String word)
    {
        String[] currentstr ={prefix,word};
        Stack<String[]> stack = new Stack<String[]>();
        stack.add(currentstr);
        while(!stack.isEmpty())
        {
            currentstr = stack.pop();
            String currentPrefix = currentstr[0];
            String currentWord = currentstr[1];
            if(currentWord.equals(""))
            {
                System.out.println("Word ="+currentPrefix);
            }
            for(int i=0;i<currentWord.length();i++)
            {
                String[] newstr = new String[2];
                newstr[0]=currentPrefix + String.valueOf(currentWord.charAt(i));
                newstr[1] = currentWord.substring(0, i);
                if(i<currentWord.length()-1)
                {
                    newstr[1] = newstr[1]+currentWord.substring(i+1);
                }
                stack.push(newstr);
            }

        }

    }
nnc
la source
0

Cela peut être fait de manière itérative en insérant simplement chaque lettre de la chaîne à son tour dans tous les emplacements des résultats partiels précédents.

Nous commençons par [A], qui , avec Bdevient [BA, AB], et C, [CBA, BCA, BAC, CAB, etc].

Le temps d'exécution serait O(n!), ce qui, pour le cas de test ABCD, est 1 x 2 x 3 x 4.

Dans le produit ci-dessus, le 1est pour A, le 2est pour B, etc.

Échantillon de fléchettes:

void main() {

  String insertAt(String a, String b, int index)
  {
    return a.substring(0, index) + b + a.substring(index);
  }

  List<String> Permute(String word) {

    var letters = word.split('');

    var p_list = [ letters.first ];

    for (var c in letters.sublist(1)) {

      var new_list = [ ];

      for (var p in p_list)
        for (int i = 0; i <= p.length; i++)
          new_list.add(insertAt(p, c, i));

      p_list = new_list;
    }

    return p_list;
  }

  print(Permute("ABCD"));

}
Troy Dawson
la source
0

Voici une implémentation java:

/* All Permutations of a String */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Complexity O(n*n!) */
class Ideone
{
     public static ArrayList<String> strPerm(String str, ArrayList<String> list)
     {
        int len = str.length();
        if(len==1){
            list.add(str);
            return list;
        }

        list = strPerm(str.substring(0,len-1),list);
        int ls = list.size();
        char ap = str.charAt(len-1);
        for(int i=0;i<ls;i++){
            String temp = list.get(i);
            int tl = temp.length();
            for(int j=0;j<=tl;j++){
                list.add(temp.substring(0,j)+ap+temp.substring(j,tl));  
            }
        }

        while(true){
            String temp = list.get(0);
            if(temp.length()<len)
                list.remove(temp);
            else
                break;
        }

        return list;
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        String str = "abc";
        ArrayList<String> list = new ArrayList<>();

        list = strPerm(str,list);
        System.out.println("Total Permutations : "+list.size());
        for(int i=0;i<list.size();i++)
            System.out.println(list.get(i));

    }
}

http://ideone.com/nWPb3k

Sahil Chhabra
la source