Generieren Sie eine Liste aller möglichen Permutationen einer Zeichenfolge

Antworten:

70

Es gibt verschiedene Möglichkeiten, dies zu tun. Gängige Methoden verwenden Rekursion, Memoisierung oder dynamische Programmierung. Die Grundidee besteht darin, dass Sie eine Liste aller Zeichenfolgen der Länge 1 erstellen und dann in jeder Iteration für alle in der letzten Iteration erstellten Zeichenfolgen die mit jedem Zeichen in der Zeichenfolge verkettete Zeichenfolge einzeln hinzufügen. (Der Variablenindex im folgenden Code verfolgt den Beginn der letzten und der nächsten Iteration.)

Ein Pseudocode:

list = originalString.split('')
index = (0,0)
list = [""]
for iteration n in 1 to y:
  index = (index[1], len(list))
  for string s in list.subset(index[0] to end):
    for character c in originalString:
      list.add(s + c)

Sie müssten dann alle Zeichenfolgen mit einer Länge von weniger als x entfernen. Dies sind die ersten (x-1) * len (originalString) -Einträge in der Liste.

alumb
quelle
4
Warum zuerst die Liste der Elemente speichern und dann löschen? (Bezug nehmend auf Zeile 1 und 3 im Pseudocode).
Håvard Geithus
6
Was ist y (Zeile 4)?
Jaseem
7
@Jaseem Aus der Frage: "Alle möglichen Permutationen einer Zeichenfolge zwischen x und y Zeichen in der Länge"
ck_
39

Es ist besser, Backtracking zu verwenden

#include <stdio.h>
#include <string.h>

void swap(char *a, char *b) {
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void print(char *a, int i, int n) {
    int j;
    if(i == n) {
        printf("%s\n", a);
    } else {
        for(j = i; j <= n; j++) {
            swap(a + i, a + j);
            print(a, i + 1, n);
            swap(a + i, a + j);
        }
    }
}

int main(void) {
    char a[100];
    gets(a);
    print(a, 0, strlen(a) - 1);
    return 0;
}
Unnykrishnan S.
quelle
3
Beste Lösung everrrrrrrrr
GrowinMan
25

Du wirst eine Menge Saiten bekommen, das ist sicher ...

\ sum_ {i = x} ^ y {\ frac {r!} {{(ri)}!}}
Wobei Sie sie mit x und y definieren und r die Anzahl der Zeichen ist, aus denen wir auswählen - wenn ich Sie richtig verstehe. Sie sollten diese auf jeden Fall nach Bedarf generieren und nicht schlampig werden und beispielsweise ein Powerset generieren und dann die Länge der Zeichenfolgen filtern.

Das Folgende ist definitiv nicht der beste Weg, um diese zu generieren, aber es ist trotzdem interessant.

Knuth (Band 4, Faszikel 2, 7.2.1.3) sagt uns, dass die (s, t) -Kombination äquivalent zu s + 1 Dingen ist, die t zu einem Zeitpunkt mit Wiederholung genommen werden - eine (s, t) -Kombination ist eine Notation, die von verwendet wird Knuth das ist gleich {t \ wähle {s + t}. Wir können dies herausfinden, indem wir zuerst jede (s, t) -Kombination in binärer Form (also der Länge (s + t)) erzeugen und die Anzahl der Nullen links von jeder 1 zählen.

10001000011101 -> wird zur Permutation: {0, 3, 4, 4, 4, 1}

Nlucaroni
quelle
15

Nicht rekursive Lösung nach Knuth, Python-Beispiel:

def nextPermutation(perm):
    k0 = None
    for i in range(len(perm)-1):
        if perm[i]<perm[i+1]:
            k0=i
    if k0 == None:
        return None

    l0 = k0+1
    for i in range(k0+1, len(perm)):
        if perm[k0] < perm[i]:
            l0 = i

    perm[k0], perm[l0] = perm[l0], perm[k0]
    perm[k0+1:] = reversed(perm[k0+1:])
    return perm

perm=list("12345")
while perm:
    print perm
    perm = nextPermutation(perm)
Rocksportrocker
quelle
2
Tatsächlich funktioniert dies nicht , wenn die Zeichenfolge nicht sortiert ist. Wenn Sie es mit "54321"nur EINEM String versuchen, wird (selbst) angezeigt .
Tonjo
1
Interessant ist, dass nextPermutation()es zustandslos ist - es werden nur die Eingaben zum Permutieren benötigt und Indizes werden nicht von Iteration zu Iteration verwaltet. Dies ist möglich, indem angenommen wird, dass die anfängliche Eingabe sortiert wurde, und Indizes ( k0und l0) selbst gefunden werden, basierend darauf, wo die Reihenfolge beibehalten wird. Durch Sortieren einer Eingabe wie "54321" -> "12345" kann dieser Algorithmus alle erwarteten Permutationen finden. Da es jedoch eine Menge zusätzlicher Arbeit kostet, diese Indizes für jede generierte Permutation neu zu finden, gibt es effizientere Möglichkeiten, dies nicht rekursiv zu tun.
spaaarky21
13

Sie können sich " Effizientes Aufzählen der Teilmengen einer Menge " ansehen , in dem ein Algorithmus beschrieben wird, mit dem Sie einen Teil Ihrer Wünsche erfüllen können - generieren Sie schnell alle Teilmengen von N Zeichen von der Länge x bis y. Es enthält eine Implementierung in C.

Für jede Teilmenge müssten Sie noch alle Permutationen generieren. Wenn Sie beispielsweise 3 Zeichen von "abcde" möchten, gibt Ihnen dieser Algorithmus "abc", "abd", "abe" ... aber Sie müssten jedes einzelne permutieren, um "acb", "bac", zu erhalten. "bca" usw.

AShelly
quelle
13

Einige funktionierende Java-Codes basierend auf Sarps Antwort :

public class permute {

    static void permute(int level, String permuted,
                    boolean used[], String original) {
        int length = original.length();
        if (level == length) {
            System.out.println(permuted);
        } else {
            for (int i = 0; i < length; i++) {
                if (!used[i]) {
                    used[i] = true;
                    permute(level + 1, permuted + original.charAt(i),
                       used, original);
                    used[i] = false;
                }
            }
        }
    }

    public static void main(String[] args) {
        String s = "hello";
        boolean used[] = {false, false, false, false, false};
        permute(0, "", used, s);
    }
}
Lazer
quelle
Beachten Sie als Kommentar, dass für eine Zeichenfolge mit wiederholten Zeichen keine eindeutigen Permutationen erzeugt werden. Dies könnte mit einem Hash gelöst werden, aber das könnte ein Problem mit langen Zeichenfolgen sein.
Glenn
8
Möglicherweise möchten Sie char-Arrays anstelle von Zeichenfolgen verwenden, um die Ausführung zu beschleunigen, da Zeichenfolgen in Java unveränderlich sind.
Abhijeet Kashnia
13

Hier ist eine einfache Lösung in C #.

Es werden nur die unterschiedlichen Permutationen einer bestimmten Zeichenfolge generiert.

    static public IEnumerable<string> permute(string word)
    {
        if (word.Length > 1)
        {

            char character = word[0];
            foreach (string subPermute in permute(word.Substring(1)))
            {

                for (int index = 0; index <= subPermute.Length; index++)
                {
                    string pre = subPermute.Substring(0, index);
                    string post = subPermute.Substring(index);

                    if (post.Contains(character))
                            continue;                       

                    yield return pre + character + post;
                }

            }
        }
        else
        {
            yield return word;
        }
    }
Prakhar Gupta
quelle
12

Hier gibt es viele gute Antworten. Ich schlage auch eine sehr einfache rekursive Lösung in C ++ vor.

#include <string>
#include <iostream>

template<typename Consume>
void permutations(std::string s, Consume consume, std::size_t start = 0) {
    if (start == s.length()) consume(s);
    for (std::size_t i = start; i < s.length(); i++) {
        std::swap(s[start], s[i]);
        permutations(s, consume, start + 1);
    }
}

int main(void) {
    std::string s = "abcd";
    permutations(s, [](std::string s) {
        std::cout << s << std::endl;
    });
}

Hinweis : Zeichenfolgen mit wiederholten Zeichen erzeugen keine eindeutigen Permutationen.

gd1
quelle
9

Ich habe das gerade in Ruby schnell ausgepeitscht:

def perms(x, y, possible_characters)
  all = [""]
  current_array = all.clone
  1.upto(y) { |iteration|
    next_array = []
    current_array.each { |string|
      possible_characters.each { |c|
        value = string + c
        next_array.insert next_array.length, value
        all.insert all.length, value
      }
    }
    current_array = next_array
  }
  all.delete_if { |string| string.length < x }
end

Möglicherweise suchen Sie in der Sprach-API nach integrierten Funktionen für Permutationstypen, und Sie können möglicherweise optimierten Code schreiben. Wenn die Zahlen jedoch so hoch sind, bin ich mir nicht sicher, ob es viele Möglichkeiten gibt, viele Ergebnisse zu erzielen .

Wie auch immer, die Idee hinter dem Code ist, mit einer Zeichenfolge der Länge 0 zu beginnen und dann alle Zeichenfolgen der Länge Z zu verfolgen, wobei Z die aktuelle Größe in der Iteration ist. Gehen Sie dann jede Zeichenfolge durch und hängen Sie jedes Zeichen an jede Zeichenfolge an. Entfernen Sie am Ende alle, die unter dem x-Schwellenwert lagen, und geben Sie das Ergebnis zurück.

Ich habe es nicht mit potenziell bedeutungslosen Eingaben getestet (Nullzeichenliste, seltsame Werte von x und y usw.).

Mike Stone
quelle
11
Dieser Code ist FALSCH. Es werden ungültige Permutationen generiert, z. B. solche mit wiederholten Zeichen. Für die Zeichenfolge "abc" werden beispielsweise die folgenden Permutationen der Größe 3 generiert: ["aaa", "aab", "aac", "aba", "abb", "abc", "aca", "acb", "acc", "baa", "bab", "bac", "bba", "bbb", "bbc", "bca", "bcb", "bcc", "caa", "cab", "cac "," cba "," cbb "," cbc "," cca "," ccb "," ccc "]. Das ist falsch.
pmc255
8

Dies ist eine Übersetzung von Mikes Ruby-Version in Common Lisp:

(defun perms (x y original-string)
  (loop with all = (list "")
        with current-array = (list "")
        for iteration from 1 to y
        do (loop with next-array = nil
                 for string in current-array
                 do (loop for c across original-string
                          for value = (concatenate 'string string (string c))
                          do (push value next-array)
                             (push value all))
                    (setf current-array (reverse next-array)))
        finally (return (nreverse (delete-if #'(lambda (el) (< (length el) x)) all)))))

Und eine andere Version, die etwas kürzer ist und mehr Loop-Funktionen bietet:

(defun perms (x y original-string)
  (loop repeat y
        collect (loop for string in (or (car (last sets)) (list ""))
                      append (loop for c across original-string
                                   collect (concatenate 'string string (string c)))) into sets
        finally (return (loop for set in sets
                              append (loop for el in set when (>= (length el) x) collect el)))))
Martin
quelle
8

Hier ist ein einfaches Wort C # rekursive Lösung:

Methode:

public ArrayList CalculateWordPermutations(string[] letters, ArrayList words, int index)
        {
            bool finished = true;
            ArrayList newWords = new ArrayList();
            if (words.Count == 0)
            {
                foreach (string letter in letters)
                {
                    words.Add(letter);
                }
            }

            for(int j=index; j<words.Count; j++)
            {
                string word = (string)words[j];
                for(int i =0; i<letters.Length; i++)
                {
                    if(!word.Contains(letters[i]))
                    {
                        finished = false;
                        string newWord = (string)word.Clone();
                        newWord += letters[i];
                        newWords.Add(newWord);
                    }
                }
            }

            foreach (string newWord in newWords)
            {   
                words.Add(newWord);
            }

            if(finished  == false)
            {
                CalculateWordPermutations(letters, words, words.Count - newWords.Count);
            }
            return words;
        }

Berufung:

string[] letters = new string[]{"a","b","c"};
ArrayList words = CalculateWordPermutations(letters, new ArrayList(), 0);
Crackerjack
quelle
8

... und hier ist die C-Version:

void permute(const char *s, char *out, int *used, int len, int lev)
{
    if (len == lev) {
        out[lev] = '\0';
        puts(out);
        return;
    }

    int i;
    for (i = 0; i < len; ++i) {
        if (! used[i])
            continue;

        used[i] = 1;
        out[lev] = s[i];
        permute(s, out, used, len, lev + 1);
        used[i] = 0;
    }
    return;
}
Peyman
quelle
8

permutieren (ABC) -> A.perm (BC) -> A.perm [B.perm (C)] -> A.perm [( * B C), (C B * )] -> [( * A BC ), (B A C), (BC A * ), ( * A CB), (C A B), (CB A * )] Um Duplikate beim Einfügen jedes Alphabets zu entfernen, prüfen Sie, ob die vorherige Zeichenfolge mit demselben Alphabet endet (warum? -Übung)

public static void main(String[] args) {

    for (String str : permStr("ABBB")){
        System.out.println(str);
    }
}

static Vector<String> permStr(String str){

    if (str.length() == 1){
        Vector<String> ret = new Vector<String>();
        ret.add(str);
        return ret;
    }

    char start = str.charAt(0);
    Vector<String> endStrs = permStr(str.substring(1));
    Vector<String> newEndStrs = new Vector<String>();
    for (String endStr : endStrs){
        for (int j = 0; j <= endStr.length(); j++){
            if (endStr.substring(0, j).endsWith(String.valueOf(start)))
                break;
            newEndStrs.add(endStr.substring(0, j) + String.valueOf(start) + endStr.substring(j));
        }
    }
    return newEndStrs;
}

Druckt alle Permutationen ohne Duplikate

Raj
quelle
8

Rekursive Lösung in C ++

int main (int argc, char * const argv[]) {
        string s = "sarp";
        bool used [4];
        permute(0, "", used, s);
}

void permute(int level, string permuted, bool used [], string &original) {
    int length = original.length();

    if(level == length) { // permutation complete, display
        cout << permuted << endl;
    } else {
        for(int i=0; i<length; i++) { // try to add an unused character
            if(!used[i]) {
                used[i] = true;
                permute(level+1, original[i] + permuted, used, original); // find the permutations starting with this string
                used[i] = false;
            }
        }
}
Sarp Centel
quelle
7

Wenn Sie sich in Perl auf das Kleinbuchstabenalphabet beschränken möchten, können Sie Folgendes tun:

my @result = ("a" .. "zzzz");

Dies gibt alle möglichen Zeichenfolgen zwischen 1 und 4 Zeichen mit Kleinbuchstaben. Für Großbuchstaben wechseln Sie "a"zu "A"und "zzzz"zu "ZZZZ".

Für gemischte Fälle wird es viel schwieriger und wahrscheinlich mit einem solchen eingebauten Perl-Operator nicht machbar.

Chris Lutz
quelle
7

Ruby Antwort, die funktioniert:

class String
  def each_char_with_index
    0.upto(size - 1) do |index|
      yield(self[index..index], index)
    end
  end
  def remove_char_at(index)
    return self[1..-1] if index == 0
    self[0..(index-1)] + self[(index+1)..-1]
  end
end

def permute(str, prefix = '')
  if str.size == 0
    puts prefix
    return
  end
  str.each_char_with_index do |char, index|
    permute(str.remove_char_at(index), prefix + char)
  end
end

# example
# permute("abc")
Kem Mason
quelle
Für einen ausgefallenen Liner in Ruby: stackoverflow.com/questions/5773961/…
Dojosto
6
import java.util.*;

public class all_subsets {
    public static void main(String[] args) {
        String a = "abcd";
        for(String s: all_perm(a)) {
            System.out.println(s);
        }
    }

    public static Set<String> concat(String c, Set<String> lst) {
        HashSet<String> ret_set = new HashSet<String>();
        for(String s: lst) {
            ret_set.add(c+s);
        }
        return ret_set;
    }

    public static HashSet<String> all_perm(String a) {
        HashSet<String> set = new HashSet<String>();
        if(a.length() == 1) {
            set.add(a);
        } else {
            for(int i=0; i<a.length(); i++) {
                set.addAll(concat(a.charAt(i)+"", all_perm(a.substring(0, i)+a.substring(i+1, a.length()))));
            }
        }
        return set;
    }
}
Swapneel Patil
quelle
6

Die folgende Java-Rekursion druckt alle Permutationen einer bestimmten Zeichenfolge:

//call it as permut("",str);

public void permut(String str1,String str2){
    if(str2.length() != 0){
        char ch = str2.charAt(0);
        for(int i = 0; i <= str1.length();i++)
            permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()),
                     str2.substring(1,str2.length()));
    }else{
    System.out.println(str1);
    }
}

Es folgt die aktualisierte Version der obigen "permut" -Methode, mit der n! (n faktorielle) weniger rekursive Aufrufe im Vergleich zur obigen Methode

//call it as permut("",str);

public void permut(String str1,String str2){
   if(str2.length() > 1){
       char ch = str2.charAt(0);
       for(int i = 0; i <= str1.length();i++)
          permut(str1.substring(0,i) + ch + str1.substring(i,str1.length()),
                 str2.substring(1,str2.length()));
   }else{
    char ch = str2.charAt(0);
    for(int i = 0; i <= str1.length();i++)
        System.out.println(str1.substring(0,i) + ch +    str1.substring(i,str1.length()),
                 str2.substring(1,str2.length()));
   }
}
Ramy
quelle
Dies ist die sauberste Lösung, und ich glaube, ich habe sie schon einmal in dem Buch "Cracking the Coding Interview"
Tao Zhang
1
@TaoZhang danke für die Ergänzung, ich habe es nicht von irgendwoher kopiert, aber es ist möglich, dass jemand ein ähnliches Algo erstellt hat. Wie auch immer, ich habe den obigen Code für weniger rekursive Aufrufe aktualisiert
Ramy
5

Ich bin mir nicht sicher, warum Sie das überhaupt tun möchten. Die resultierende Menge für mäßig große Werte von x und y ist riesig und wächst exponentiell, wenn x und / oder y größer werden.

Nehmen wir an, Ihr Satz möglicher Zeichen besteht aus 26 Kleinbuchstaben des Alphabets, und Sie fordern Ihre Anwendung auf, alle Permutationen mit der Länge = 5 zu generieren. Vorausgesetzt, Ihnen geht nicht der Speicher aus, erhalten Sie 11.881.376 (dh 26 hoch) von 5) Saiten zurück. Wenn Sie diese Länge auf 6 erhöhen, erhalten Sie 308.915.776 Saiten zurück. Diese Zahlen werden sehr schnell schmerzhaft groß.

Hier ist eine Lösung, die ich in Java zusammengestellt habe. Sie müssen zwei Laufzeitargumente angeben (entsprechend x und y). Habe Spaß.

public class GeneratePermutations {
    public static void main(String[] args) {
        int lower = Integer.parseInt(args[0]);
        int upper = Integer.parseInt(args[1]);

        if (upper < lower || upper == 0 || lower == 0) {
            System.exit(0);
        }

        for (int length = lower; length <= upper; length++) {
            generate(length, "");
        }
    }

    private static void generate(int length, String partial) {
        if (length <= 0) {
            System.out.println(partial);
        } else {
            for (char c = 'a'; c <= 'z'; c++) {
                generate(length - 1, partial + c);
            }
        }
    }
}
Brian Willis
quelle
Lange Zeit, aber erzeugen Sie sie nicht mit Wiederholung?
Kakira
5

Hier ist eine nicht rekursive Version, die ich mir in Javascript ausgedacht habe. Es basiert nicht auf Knuths oben nicht rekursivem, obwohl es einige Ähnlichkeiten beim Elementaustausch aufweist. Ich habe die Richtigkeit für Eingabearrays mit bis zu 8 Elementen überprüft.

Eine schnelle Optimierung wäre das Vorfliegen des outArrays und das Vermeiden push().

Die Grundidee ist:

  1. Generieren Sie bei einem einzelnen Quellarray einen ersten neuen Satz von Arrays, die das erste Element nacheinander mit jedem nachfolgenden Element austauschen, wobei die anderen Elemente jedes Mal ungestört bleiben. Beispiel: 1234 angegeben, 1234, 2134, 3214, 4231 erzeugen.

  2. Verwenden Sie jedes Array aus dem vorherigen Durchgang als Startwert für einen neuen Durchgang. Tauschen Sie jedoch anstelle des ersten Elements das zweite Element mit jedem nachfolgenden Element aus. Nehmen Sie diesmal auch nicht das ursprüngliche Array in die Ausgabe auf.

  3. Wiederholen Sie Schritt 2, bis Sie fertig sind.

Hier ist das Codebeispiel:

function oxe_perm(src, depth, index)
{
    var perm = src.slice();     // duplicates src.
    perm = perm.split("");
    perm[depth] = src[index];
    perm[index] = src[depth];
    perm = perm.join("");
    return perm;
}

function oxe_permutations(src)
{
    out = new Array();

    out.push(src);

    for (depth = 0; depth < src.length; depth++) {
        var numInPreviousPass = out.length;
        for (var m = 0; m < numInPreviousPass; ++m) {
            for (var n = depth + 1; n < src.length; ++n) {
                out.push(oxe_perm(out[m], depth, n));
            }
        }
    }

    return out;
}
Orion Elenzil
quelle
3

In Rubin:

str = "a"
100_000_000.times {puts str.next!}

Es ist ziemlich schnell, aber es wird einige Zeit dauern =). Natürlich können Sie bei "aaaaaaaa" beginnen, wenn die kurzen Saiten für Sie nicht interessant sind.

Ich hätte die eigentliche Frage vielleicht falsch interpretiert - in einem der Beiträge klang es so, als ob Sie nur eine Bruteforce-Bibliothek von Zeichenfolgen benötigen, aber in der Hauptfrage klingt es so, als müssten Sie eine bestimmte Zeichenfolge permutieren.

Ihr Problem ähnelt dem folgenden: http://beust.com/weblog/archives/000491.html (Listen Sie alle Ganzzahlen auf, in denen sich keine der Ziffern wiederholt, was dazu führte, dass viele Sprachen es mit dem Problem lösten Ocaml-Typ, der Permutationen verwendet, und ein Java-Typ, der noch eine andere Lösung verwendet).

bOR_
quelle
Ein Problem mit Ihrem Vorschlag ist, dass str.next! iteriert nicht über alle druckbaren Zeichen. In Ihrem Beispiel werden nur Kleinbuchstaben generiert - keine Interpunktion oder Großbuchstaben.
Jarsen
3

Ich brauchte das heute und obwohl die bereits gegebenen Antworten mich in die richtige Richtung wiesen, waren sie nicht ganz das, was ich wollte.

Hier ist eine Implementierung mit der Heap-Methode. Die Länge des Arrays muss mindestens 3 betragen und darf aus praktischen Gründen nicht größer als 10 sein, je nachdem, was Sie tun möchten, Geduld und Taktrate.

Bevor Sie Ihre Schleife betreten, initialisieren Sie Perm(1 To N)mit der ersten Permutation, Stack(3 To N)mit Nullen * und Levelmit 2**. Am Ende des Schleifenaufrufs NextPerm, der false zurückgibt, wenn wir fertig sind.

* VB erledigt das für Sie.

** Sie können NextPerm ein wenig ändern, um dies unnötig zu machen, aber es ist klarer.

Option Explicit

Function NextPerm(Perm() As Long, Stack() As Long, Level As Long) As Boolean
Dim N As Long
If Level = 2 Then
    Swap Perm(1), Perm(2)
    Level = 3
Else
    While Stack(Level) = Level - 1
        Stack(Level) = 0
        If Level = UBound(Stack) Then Exit Function
        Level = Level + 1
    Wend
    Stack(Level) = Stack(Level) + 1
    If Level And 1 Then N = 1 Else N = Stack(Level)
    Swap Perm(N), Perm(Level)
    Level = 2
End If
NextPerm = True
End Function

Sub Swap(A As Long, B As Long)
A = A Xor B
B = A Xor B
A = A Xor B
End Sub

'This is just for testing.
Private Sub Form_Paint()
Const Max = 8
Dim A(1 To Max) As Long, I As Long
Dim S(3 To Max) As Long, J As Long
Dim Test As New Collection, T As String
For I = 1 To UBound(A)
    A(I) = I
Next
Cls
ScaleLeft = 0
J = 2
Do
    If CurrentY + TextHeight("0") > ScaleHeight Then
        ScaleLeft = ScaleLeft - TextWidth(" 0 ") * (UBound(A) + 1)
        CurrentY = 0
        CurrentX = 0
    End If
    T = vbNullString
    For I = 1 To UBound(A)
        Print A(I);
        T = T & Hex(A(I))
    Next
    Print
    Test.Add Null, T
Loop While NextPerm(A, S, J)
J = 1
For I = 2 To UBound(A)
    J = J * I
Next
If J <> Test.Count Then Stop
End Sub

Andere Methoden werden von verschiedenen Autoren beschrieben. Knuth beschreibt zwei, eine gibt die lexikalische Ordnung an, ist aber komplex und langsam, die andere ist als Methode der einfachen Änderungen bekannt. Jie Gao und Dianjun Wang haben ebenfalls eine interessante Arbeit geschrieben.

Anonymer Feigling
quelle
2

Wenn dieser Code in Python mit allowed_charactersset to [0,1]und maximal 4 Zeichen aufgerufen wird, werden 2 ^ 4 Ergebnisse generiert:

['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']

def generate_permutations(chars = 4) :

#modify if in need!
    allowed_chars = [
        '0',
        '1',
    ]

    status = []
    for tmp in range(chars) :
        status.append(0)

    last_char = len(allowed_chars)

    rows = []
    for x in xrange(last_char ** chars) :
        rows.append("")
        for y in range(chars - 1 , -1, -1) :
            key = status[y]
            rows[x] = allowed_chars[key] + rows[x]

        for pos in range(chars - 1, -1, -1) :
            if(status[pos] == last_char - 1) :
                status[pos] = 0
            else :
                status[pos] += 1
                break;

    return rows

import sys


print generate_permutations()

Hoffe, das nützt dir. Funktioniert mit jedem Zeichen, nicht nur mit Zahlen

Aminah Nuraini
quelle
Dies sind keine Permutationen, sondern eine Teilmengenauswahl, dh ABC & 001 = C, während eine gültige Permutation alle drei Zeichen haben muss.
Schultz9999
äh? Entschuldigung, ich verstehe nicht, was du sagst. Wenn Sie es reparieren, lassen Sie eine feste Version, ich werde Community-Wiki das Ding
Droope
0

Obwohl dies Ihre Frage nicht genau beantwortet, gibt es eine Möglichkeit, jede Permutation der Buchstaben aus einer Reihe von Zeichenfolgen gleicher Länge zu generieren: Wenn Ihre Wörter beispielsweise "Kaffee", "Joomla" und "Moodle" waren, können Sie dies tun Erwarten Sie Ausgaben wie "coodle", "joodee", "joffle" usw.

Grundsätzlich ist die Anzahl der Kombinationen die (Anzahl der Wörter) hoch (Anzahl der Buchstaben pro Wort). Wählen Sie also eine Zufallszahl zwischen 0 und der Anzahl der Kombinationen - 1, konvertieren Sie diese Zahl in Basis (Anzahl der Wörter) und verwenden Sie dann jede Ziffer dieser Zahl als Indikator für das Wort, aus dem der nächste Buchstabe entnommen werden soll.

zB: im obigen Beispiel. 3 Wörter, 6 Buchstaben = 729 Kombinationen. Wählen Sie eine Zufallszahl: 465. Konvertieren Sie in Basis 3: 122020. Nehmen Sie den ersten Buchstaben von Wort 1, den zweiten von Wort 2, den dritten von Wort 2, den vierten von Wort 0 ... und Sie erhalten ... "Joofle".

Wenn Sie alle Permutationen möchten , führen Sie einfach eine Schleife von 0 bis 728 durch. Wenn Sie nur einen zufälligen Wert auswählen, ist es natürlich viel einfacher, die Buchstaben zu durchlaufen, wenn Sie eine weniger verwirrende Methode verwenden. Mit dieser Methode können Sie eine Rekursion vermeiden, wenn Sie alle Permutationen wünschen. Außerdem sehen Sie so aus, als ob Sie Maths (tm) kennen !

Wenn die Anzahl der Kombinationen zu groß ist, können Sie sie in eine Reihe kleinerer Wörter aufteilen und am Ende verketten.

nickf
quelle
0

c # iterativ:

public List<string> Permutations(char[] chars)
    {
        List<string> words = new List<string>();
        words.Add(chars[0].ToString());
        for (int i = 1; i < chars.Length; ++i)
        {
            int currLen = words.Count;
            for (int j = 0; j < currLen; ++j)
            {
                var w = words[j];
                for (int k = 0; k <= w.Length; ++k)
                {
                    var nstr = w.Insert(k, chars[i].ToString());
                    if (k == 0)
                        words[j] = nstr;
                    else
                        words.Add(nstr);
                }
            }
        }
        return words;
    }
wliao
quelle
0
def gen( x,y,list): #to generate all strings inserting y at different positions
list = []
list.append( y+x )
for i in range( len(x) ):
    list.append( func(x,0,i) + y + func(x,i+1,len(x)-1) )
return list 

def func( x,i,j ): #returns x[i..j]
z = '' 
for i in range(i,j+1):
    z = z+x[i]
return z 

def perm( x , length , list ): #perm function
if length == 1 : # base case
    list.append( x[len(x)-1] )
    return list 
else:
    lists = perm( x , length-1 ,list )
    lists_temp = lists #temporarily storing the list 
    lists = []
    for i in range( len(lists_temp) ) :
        list_temp = gen(lists_temp[i],x[length-2],lists)
        lists += list_temp 
    return lists
abkds
quelle
0
def permutation(str)
  posibilities = []
  str.split('').each do |char|
    if posibilities.size == 0
      posibilities[0] = char.downcase
      posibilities[1] = char.upcase
    else
      posibilities_count = posibilities.length
      posibilities = posibilities + posibilities
      posibilities_count.times do |i|
        posibilities[i] += char.downcase
        posibilities[i+posibilities_count] += char.upcase
      end
    end
  end
  posibilities
end

Hier ist meine Einstellung zu einer nicht rekursiven Version

Pastete
quelle
0

Die pythonische Lösung:

from itertools import permutations
s = 'ABCDEF'
p = [''.join(x) for x in permutations(s)]
Abdul Fatir
quelle
0

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