Generieren aller Permutationen einer bestimmten Zeichenfolge

418

Was ist ein eleganter Weg, um alle Permutationen einer Zeichenfolge zu finden. ZB Permutation für ba, wäre baund ab, aber was ist mit längeren Zeichenfolgen wie abcdefgh? Gibt es ein Java-Implementierungsbeispiel?

GurdeepS
quelle
3
Hier gibt es viele Antworten: stackoverflow.com/questions/361/…
Marek Sapota
Dies ist eine sehr beliebte Frage. Sie können einen Blick hier werfen: careercup.com/question?id=3861299
JJunior
9
Es gibt eine Annahme, die erwähnt werden muss. Die Charaktere sind einzigartig. Zum Beispiel gibt es für einen String "aaaa" nur eine Antwort. Um eine allgemeinere Antwort zu erhalten, können Sie die Zeichenfolgen in einem Satz speichern, um Doppelarbeit zu vermeiden
Afshin Moazami
1
Ist die Wiederholung von Zeichen erlaubt oder ist die Wiederholung von Zeichen nicht erlaubt? Kann eine einzelne Zeichenfolge mehrere Vorkommen desselben Zeichens haben?
Anderson Green
2
Lesen Sie die Theorie (oder wenn Sie wie ich faul sind, gehen Sie zu en.wikipedia.org/wiki/Permutation ) und implementieren Sie einen echten Algorithmus. Grundsätzlich können Sie eine Folge von Ordnungen von Elementen generieren (die Tatsache, dass es sich um eine Zeichenfolge handelt, ist irrelevant) und durch die Ordnungen gehen, bis Sie zum Anfang zurückkehren. Vermeiden Sie alles, was Rekursion oder String-Manipulationen beinhaltet.
CurtainDog

Antworten:

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

(über Einführung in die Programmierung in Java )

SuperJulietta
quelle
67
Die Lösung scheint von hier zu kommen. Introcs.cs.princeton.edu/java/23recursion/…
Cyber-Mönch
48
Das ist keine Raketenwissenschaft, ich habe so ziemlich die gleiche Antwort gefunden. Kleinere Änderungen: Anstatt bis zu rekursiv zu sein n==0, können Sie ein Level früher anhalten n==1und ausdrucken prefix + str.
Lambshaanxy
7
"Was ist die zeitliche und räumliche Komplexität davon?" Ohne eine Art Teilantwort-Caching ist jeder Algorithmus, der die Permutation ausgibt, o (n!), da die Ergebnismenge für die Permutationsfrage für die Eingabe faktoriell ist.
Jeremyjjbrown
9
Elegant, ja. Eine Lösung, die in ein char-Array konvertiert und ausgetauscht wird, um die Permutationen zu generieren, erfordert jedoch viel weniger Kopieren und viel weniger Müll. Auch dieser Algorithmus berücksichtigt wiederholte Zeichen nicht.
Gene
20
@AfshinMoazami Ich denke, str.substring (i + 1, n) kann durch str.substring (i + 1) ersetzt werden. Die Verwendung von str.substring (i) führt zu java.lang.StackOverflowError.
Ayusman
196

Rekursion verwenden.

  • Probieren Sie jeden Buchstaben nacheinander als ersten Buchstaben aus und ermitteln Sie dann alle Permutationen der verbleibenden Buchstaben mithilfe eines rekursiven Aufrufs.
  • Der Basisfall ist, wenn die Eingabe eine leere Zeichenfolge ist, ist die einzige Permutation die leere Zeichenfolge.
Mark Byers
quelle
3
Wie können Sie der Permute-Methode einen Rückgabetyp hinzufügen? Der Compiler kann den Rückgabetyp dieser Methode nicht bei jeder Iteration bestimmen, obwohl es sich offensichtlich um einen String-Typ handelt.
user1712095
Wie stellen Sie bei dieser Methode unterschiedliche Permutationen sicher?
Kapad
70

Hier ist meine Lösung, die auf der Idee des Buches "Cracking the Coding Interview" (P54) basiert:

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

Laufende Ausgabe der Zeichenfolge "abcd":

  • Schritt 1: Füge [a] und b zusammen: [ba, ab]

  • Schritt 2: Füge [ba, ab] und c zusammen: [cba, bca, bac, cab, acb, abc]

  • Schritt 3: Zusammenführen von [cba, bca, bac, cab, acb, abc] und 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
quelle
Seite (71) in Cracking the Coding Interview Book, 6. Auflage. :)
KarimIhab
5
Ist das wirklich eine gute Lösung? Es beruht darauf, die Ergebnisse in einer Liste zu speichern, daher gerät es für eine kurze Eingabezeichenfolge außer Kontrolle.
Androrider
Was macht die Zusammenführung?
Basavaraj Walikar
Es fügt c an jeder möglichen Position jeder Zeichenfolge in der Liste ein. Wenn die Liste also nur ["b"] enthält und c "a" ist, ist das Zusammenführungsergebnis ["ab", "ba"] hier dieselbe Lösung mit Swift gist.github. com / daniaDlbani / 3bc10e02541f9ba310d546040c5322fc
Dania Delbani
53

Von allen hier und in anderen Foren angegebenen Lösungen hat mir Mark Byers am besten gefallen. Diese Beschreibung hat mich tatsächlich zum Nachdenken und Codieren gebracht. Schade, dass ich seine Lösung nicht abstimmen kann, da ich Neuling bin.
Sowieso hier ist meine Umsetzung seiner Beschreibung

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

Ich bevorzuge diese Lösung vor der ersten in diesem Thread, da diese Lösung StringBuffer verwendet. Ich würde nicht sagen, dass meine Lösung keine temporäre Zeichenfolge erstellt (tatsächlich dort, system.out.printlnwo der toString()von StringBuffer aufgerufen wird). Ich bin jedoch der Meinung, dass dies besser ist als die erste Lösung, bei der zu viele Zeichenfolgenliterale erstellt werden. Vielleicht kann ein Performance-Typ da draußen dies in Bezug auf "Speicher" bewerten (für "Zeit" bleibt es aufgrund dieses zusätzlichen "Austauschs" bereits zurück)

Srikanth Yaradla
quelle
Warum nicht einfach machen if(index == str.length())und doPerm(str, index + 1);? Das currPosscheint hier unnötig.
Robur_131
Entschuldigung, können Sie die Frage näher erläutern? Schlagen Sie nur vor, keine zusätzlichen variablen currPos zu verwenden (die aufgrund mehrfacher Vorkommen und auch der Lesbarkeit verwendet werden), wenn nicht, fügen Sie bitte die Lösung ein, die Sie
vorschlagen möchten
Ah, ich verstehe, dass Sie die Änderung der Grundbedingung mit der Vorwärtsindizierung gemeint haben. Funktioniert gut. Nur dass die von mir vorgestellte Lösung hauptsächlich von den damals anderen Lösungen beeinflusst wurde, die häufig die abgeschnittene Zeichenfolge und nicht das Original passierten (welcher Fall 0 sinnvoll ist). Trotzdem danke fürs zeigen. Mal sehen, ob ich bearbeiten kann, es ist Jahre her, seit ich mich auf dieser Seite angemeldet habe.
Srikanth Yaradla
22

Eine sehr einfache Lösung in Java ist die Verwendung von Rekursion + Set (um Wiederholungen zu vermeiden), wenn Sie die Lösungszeichenfolgen speichern und zurückgeben möchten:

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;
}
Zerstörer
quelle
2
Was ist die zeitliche Komplexität dieses Alogrithmus?
Ashisahu
1
@ashisahu O (n!) da wir n haben! Permutationen in einer gegebenen Zeichenfolge mit n Länge.
Zok
17

Alle vorherigen Mitwirkenden haben großartige Arbeit geleistet, um den Code zu erklären und bereitzustellen. Ich dachte, ich sollte diesen Ansatz auch teilen, weil er auch jemandem helfen könnte. Die Lösung basiert auf ( Heaps 'Algorithmus )

Ein paar Dinge:

  1. Beachten Sie, dass der letzte Punkt, der im Excel abgebildet ist, nur dazu dient, Ihnen zu helfen, die Logik besser zu visualisieren. Die tatsächlichen Werte in der letzten Spalte wären also 2,1,0 (wenn wir den Code ausführen würden, weil es sich um Arrays handelt und Arrays mit 0 beginnen).

  2. Der Austauschalgorithmus basiert auf geraden oder ungeraden Werten der aktuellen Position. Es ist sehr selbsterklärend, wenn Sie sich ansehen, wo die Swap-Methode aufgerufen wird. Sie können sehen, was los ist.

Folgendes passiert: Geben Sie hier die Bildbeschreibung ein

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
quelle
11

Dieser ist ohne Rekursion

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
quelle
Diese Lösung scheint falsch zu sein. System.out.println(permute("AABBC").size());Anzeigen 45, aber tatsächlich 5! = 120
Mladen Adamovic
11

Verwenden wir die Eingabe abc als Beispiel .

Beginnen Sie mit nur dem letzten Element ( c) in einer Menge ( ["c"]), fügen Sie dann das vorletzte Element ( b) an der Vorderseite, am Ende und an allen möglichen Positionen in der Mitte hinzu und machen Sie es ["bc", "cb"]dann auf die gleiche Weise zum nächsten Element von der Rückseite ( a) zu jeder Zeichenfolge im Set, die es macht:

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

Also gesamte 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
quelle
1
Ich habe deine Lösung geliebt. Sehr intuitiv und gut erklärt. Vielen Dank.
user2585781
9

Nun, hier ist eine elegante, nicht rekursive O (n!) Lösung:

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
quelle
Diese Lösung funktioniert nur, wenn das Wort weniger als 4 Buchstaben enthält. Andernfalls enthält nur die Hälfte des resultierenden Arrays eindeutige Wörter.
Maksim Maksimov
5

Eine der einfachen Lösungen könnte darin bestehen, die Zeichen mit zwei Zeigern rekursiv auszutauschen.

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
quelle
Dies ähnelt der hier angegebenen Lösung: geeksforgeeks.org/… mit Backtracking und Zeitkomplexität O (n * n!).
Nakul Kumar
5

Python-Implementierung

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
quelle
4

das hat bei mir funktioniert ..

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
quelle
3

Rekursion verwenden.

Wenn die Eingabe eine leere Zeichenfolge ist, ist die einzige Permutation eine leere Zeichenfolge. Versuchen Sie, jeden Buchstaben in der Zeichenfolge als ersten Buchstaben festzulegen, und ermitteln Sie dann alle Permutationen der verbleibenden Buchstaben mithilfe eines rekursiven Aufrufs.

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
quelle
3

Lassen Sie mich versuchen, dieses Problem mit Kotlin anzugehen:

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

Kernkonzept: Lange Liste in kleinere Liste + Rekursion aufteilen

Lange Antwort mit Beispielliste [1, 2, 3, 4]:

Selbst für eine Liste von 4 wird es schon verwirrend, alle möglichen Permutationen in Ihrem Kopf aufzulisten, und was wir tun müssen, ist genau das zu vermeiden. Es ist für uns leicht zu verstehen, wie alle Permutationen der Liste der Größen 0, 1 und 2 erstellt werden. Alles, was wir tun müssen, ist, sie in eine dieser Größen zu zerlegen und sie wieder richtig zu kombinieren. Stellen Sie sich eine Jackpot-Maschine vor: Dieser Algorithmus dreht sich von rechts nach links und schreibt auf

  1. Geben Sie leer / Liste von 1 zurück, wenn die Listengröße 0 oder 1 ist
  2. Behandeln Sie, wenn die Listengröße 2 ist (z. B. [3, 4]), und generieren Sie die 2 Permutationen ([3, 4] & [4, 3]).
  3. Markieren Sie dies für jedes Element als das letzte im letzten und suchen Sie alle Permutationen für den Rest des Elements in der Liste. (zB [4] auf den Tisch legen und [1, 2, 3] erneut in die Permutation werfen)
  4. Setzen Sie sich nun bei aller Permutation wieder an das Ende der Liste (z. B.: [1, 2, 3] [, 4], [1, 3, 2] [, 4], [2, 3, 1] [, 4], ...)
Louis Tsai
quelle
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
quelle
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
quelle
2

Hier ist eine einfache minimalistische rekursive Lösung in 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
quelle
2

Wir können Fakultät verwenden, um herauszufinden, wie viele Zeichenfolgen mit einem bestimmten Buchstaben begonnen haben.

Beispiel: Nehmen Sie die Eingabe abcd. (3!) == 6Zeichenfolgen beginnen mit jedem Buchstaben von 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
quelle
2

Dies habe ich durch grundlegendes Verständnis von Permutationen und rekursiven Funktionsaufrufen getan. Dauert etwas, ist aber unabhängig.

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

das erzeugt Ausgabe als[abc, acb, bac, bca, cab, cba] .

Grundlegende Logik dahinter ist

Betrachten Sie es für jedes Zeichen als 1. Zeichen und finden Sie die Kombinationen der verbleibenden Zeichen. zB [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}

Und dann jede rekursiv aufrufen [bc], [ac]und [ab]unabhängig.

Shabbir Essaji
quelle
2

Java-Implementierung ohne Rekursion

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
quelle
1

// füge jedes Zeichen in eine Arrayliste ein

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
quelle
Ich finde nicht , diese Antwort nützlich , da es keine Erklärung enthält und es verwendet den gleichen Algorithmus wie ein paar andere Antworten , die tun , eine Erklärung geben.
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
quelle
1

Eine andere einfache Möglichkeit besteht darin, die Zeichenfolge zu durchlaufen, das noch nicht verwendete Zeichen auszuwählen und in einen Puffer zu legen. Die Schleife wird fortgesetzt, bis die Puffergröße der Zeichenfolgenlänge entspricht. Ich mag diese Back-Tracking-Lösung besser, weil:

  1. Einfach zu verstehen
  2. Einfache Vermeidung von Doppelarbeit
  3. Die Ausgabe ist sortiert

Hier ist der Java-Code:

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

Eingangsstr: 1231

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

Es wurde festgestellt, dass die Ausgabe sortiert ist und kein doppeltes Ergebnis vorliegt.

jeantimex
quelle
1

Eine Rekursion ist nicht erforderlich, auch wenn Sie eine Permutation direkt berechnen können . Diese Lösung verwendet Generika, um ein beliebiges Array zu permutieren.

Hier finden Sie eine gute Information zu diesem Algorithmus.

Für C # -Entwickler ist hier eine nützlichere Implementierung.

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

Dieser Algorithmus hat eine zeitliche und räumliche Komplexität von O (N) , um jede Permutation zu berechnen .

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
quelle
1

Permutation von String:

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
quelle
1

Hier ist eine weitere einfachere Methode zur Permutation eines Strings.

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
quelle
1

Eine Java-Implementierung zum Drucken aller Permutationen einer bestimmten Zeichenfolge unter Berücksichtigung doppelter Zeichen und zum Drucken nur eindeutiger Zeichen lautet wie folgt:

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
quelle
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
quelle
0

Dies kann iterativ erfolgen, indem einfach jeder Buchstabe der Zeichenfolge nacheinander an allen Stellen der vorherigen Teilergebnisse eingefügt wird.

Wir beginnen mit [A], was mit Bwird [BA, AB]und mit C, [CBA, BCA, BAC, CAB, etc].

Die Laufzeit wäre O(n!), was für den Testfall ABCDist 1 x 2 x 3 x 4.

In dem obigen Produkt ist das 1für A, das 2ist für Busw.

Pfeilprobe:

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
quelle
0

Hier ist eine Java-Implementierung:

/* 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
quelle