Ich möchte eine Funktion schreiben, die ein Array von Buchstaben als Argument und eine Anzahl dieser Buchstaben zur Auswahl verwendet.
Angenommen, Sie geben ein Array mit 8 Buchstaben an und möchten 3 Buchstaben daraus auswählen. Dann sollten Sie bekommen:
8! / ((8 - 3)! * 3!) = 56
Arrays (oder Wörter) bestehen im Gegenzug aus jeweils 3 Buchstaben.
algorithm
combinations
ique
quelle
quelle
Antworten:
Kunst der Computerprogrammierung Band 4: Fascicle 3 enthält eine Menge davon, die möglicherweise besser zu Ihrer speziellen Situation passen, als ich es beschreibe.
Gray Codes
Ein Problem, auf das Sie stoßen werden, ist natürlich der Speicher. Ziemlich schnell treten Probleme mit 20 Elementen in Ihrem Satz auf - 20 C 3 = 1140. Wenn Sie den Satz durchlaufen möchten, verwenden Sie am besten ein modifiziertes Grau Code-Algorithmus, damit Sie nicht alle im Speicher halten. Diese erzeugen die nächste Kombination aus der vorherigen und vermeiden Wiederholungen. Es gibt viele davon für verschiedene Zwecke. Wollen wir die Unterschiede zwischen aufeinanderfolgenden Kombinationen maximieren? minimieren? und so weiter.
Einige der Originalarbeiten, die Gray-Codes beschreiben:
Hier sind einige andere Artikel zum Thema:
Chase's Twiddle (Algorithmus)
Phillip J Chase, " Algorithmus 382: Kombinationen von M aus N Objekten " (1970)
Der Algorithmus in C ...
Index der Kombinationen in lexikographischer Reihenfolge (Buckles-Algorithmus 515)
Sie können eine Kombination auch anhand ihres Index (in lexikografischer Reihenfolge) referenzieren. Wenn wir erkennen, dass sich der Index basierend auf dem Index von rechts nach links ändern sollte, können wir etwas konstruieren, das eine Kombination wiederherstellen sollte.
Wir haben also eine Menge {1,2,3,4,5,6} ... und wir wollen drei Elemente. Nehmen wir an, {1,2,3} wir können sagen, dass der Unterschied zwischen den Elementen eins und in Ordnung und minimal ist. {1,2,4} hat eine Änderung und ist lexikografisch die Nummer 2. Die Anzahl der 'Änderungen' an der letzten Stelle macht also eine Änderung der lexikografischen Reihenfolge aus. Der zweite Platz mit einer Änderung {1,3,4} hat eine Änderung, führt jedoch zu mehr Änderungen, da er an zweiter Stelle steht (proportional zur Anzahl der Elemente in der ursprünglichen Menge).
Die Methode, die ich beschrieben habe, ist eine Dekonstruktion, wie es scheint, von der Menge bis zum Index müssen wir das Gegenteil tun - was viel schwieriger ist. So löst Buckles das Problem. Ich habe ein C geschrieben, um sie mit geringfügigen Änderungen zu berechnen. Ich habe den Index der Mengen anstelle eines Zahlenbereichs verwendet, um die Menge darzustellen, also arbeiten wir immer von 0 ... n. Hinweis:
Index der Kombinationen in lexikographischer Reihenfolge (McCaffrey)
Es gibt noch einen anderen Weg : Das Konzept ist leichter zu verstehen und zu programmieren, aber ohne die Optimierungen von Buckles. Glücklicherweise werden auch keine doppelten Kombinationen erzeugt:
Das Set , das maximiert , wo .
Zum Beispiel :
27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Die 27. lexikografische Kombination von vier Dingen lautet also: {1,2,5,6}, das sind die Indizes aller Mengen, die Sie betrachten möchten. Das folgende Beispiel (OCaml) erfordert einechoose
Funktion, die dem Leser überlassen bleibt:Ein kleiner und einfacher Kombinationsiterator
Die folgenden zwei Algorithmen werden für didaktische Zwecke bereitgestellt. Sie implementieren einen Iterator und eine (allgemeinere) Ordner-Gesamtkombination. Sie sind so schnell wie möglich und haben die Komplexität O ( n C k ). Der Speicherverbrauch ist begrenzt durch
k
.Wir beginnen mit dem Iterator, der für jede Kombination eine vom Benutzer bereitgestellte Funktion aufruft
Eine allgemeinere Version ruft die vom Benutzer bereitgestellte Funktion zusammen mit der Statusvariablen ab dem Anfangszustand auf. Da wir den Zustand zwischen verschiedenen Zuständen übergeben müssen, verwenden wir nicht die for-Schleife, sondern die Rekursion.
quelle
In C #:
Verwendungszweck:
Ergebnis:
quelle
var result = new[] { 1, 2, 3, 4, 5 }.Combinations(3);
Kurze Java-Lösung:
Ergebnis wird sein
quelle
Darf ich meine rekursive Python-Lösung für dieses Problem vorstellen?
Anwendungsbeispiel:
Ich mag es wegen seiner Einfachheit.
quelle
len(tuple(itertools.combinations('abcdefgh',3)))
wird das gleiche in Python mit weniger Code erreichen.for i in xrange(len(elements) - length + 1):
? In Python spielt das keine Rolle, da das Verlassen des Slice-Index ordnungsgemäß behandelt wird, aber es ist der richtige Algorithmus.Nehmen wir an, Ihre Buchstabenreihe sieht folgendermaßen aus: "ABCDEFGH". Sie haben drei Indizes (i, j, k), die angeben, welche Buchstaben Sie für das aktuelle Wort verwenden werden. Sie beginnen mit:
Zuerst variierst du k, also sieht der nächste Schritt so aus:
Wenn Sie das Ende erreicht haben, fahren Sie fort und variieren j und dann wieder k.
Sobald Sie j erreicht haben, beginnen Sie auch, i zu variieren.
In Code geschrieben sieht das ungefähr so aus
quelle
Der folgende rekursive Algorithmus wählt alle k-Element-Kombinationen aus einer geordneten Menge aus:
i
Ihrer Kombinationi
mit jeder der Kombinationen vonk-1
Elementen, die rekursiv aus der Menge der Elemente ausgewählt wurden, die größer als sindi
.Wiederholen Sie die obigen Schritte für jeden
i
im Set.Es ist wichtig, dass Sie den Rest der Elemente als größer als auswählen
i
, um Wiederholungen zu vermeiden. Auf diese Weise wird [3,5] nur einmal ausgewählt, da [3] mit [5] kombiniert wird, anstatt zweimal (die Bedingung beseitigt [5] + [3]). Ohne diese Bedingung erhalten Sie Variationen anstelle von Kombinationen.quelle
In C ++ erzeugt die folgende Routine alle Kombinationen des Längenabstands (first, k) zwischen dem Bereich [first, last]:
Es kann folgendermaßen verwendet werden:
Dadurch wird Folgendes gedruckt:
quelle
being
undbegin
mits.begin()
undend
mits.end()
. Der Code folgt genau dem STL-next_permutation
Algorithmus, der hier ausführlicher beschrieben wird.Ich fand diesen Thread nützlich und dachte, ich würde eine Javascript-Lösung hinzufügen, die Sie in Firebug einfügen können. Abhängig von Ihrer JS-Engine kann es einige Zeit dauern, wenn die Startzeichenfolge groß ist.
Die Ausgabe sollte wie folgt sein:
quelle
quelle
Kurzes Beispiel in Python:
Zur Erläuterung wird die rekursive Methode anhand des folgenden Beispiels beschrieben:
Beispiel: ABCDE
Alle Kombinationen von 3 wären:
quelle
Einfacher rekursiver Algorithmus in Haskell
Wir definieren zunächst den Sonderfall, dh die Auswahl von Nullelementen. Es wird ein einzelnes Ergebnis erzeugt, bei dem es sich um eine leere Liste handelt (dh eine Liste, die eine leere Liste enthält).
Für n> 0
x
geht jedes Element der Liste durch undxs
ist jedes Element danachx
.rest
wähltn - 1
Elemente ausxs
einem rekursiven Aufruf von auscombinations
. Das Endergebnis der Funktion ist eine Liste, in der jedes Elementx : rest
(dh eine Liste mitx
Kopf undrest
Schwanz) für jeden unterschiedlichen Wert vonx
und angegeben istrest
.Und da Haskell faul ist, wird die Liste natürlich nach Bedarf nach und nach generiert, sodass Sie teilweise exponentiell große Kombinationen auswerten können.
quelle
Und hier kommt Großvater COBOL, die viel bösartige Sprache.
Nehmen wir ein Array von 34 Elementen mit jeweils 8 Bytes an (rein willkürliche Auswahl). Die Idee ist, alle möglichen 4-Element-Kombinationen aufzulisten und in ein Array zu laden.
Wir verwenden 4 Indizes, jeweils einen für jede Position in der Gruppe von 4
Das Array wird wie folgt verarbeitet:
Wir variieren idx4 von 4 bis zum Ende. Für jedes idx4 erhalten wir eine eindeutige Kombination von Vierergruppen. Wenn idx4 am Ende des Arrays ankommt, erhöhen wir idx3 um 1 und setzen idx4 auf idx3 + 1. Dann führen wir idx4 wieder bis zum Ende aus. Wir gehen auf diese Weise vor und erweitern idx3, idx2 bzw. idx1, bis die Position von idx1 vom Ende des Arrays weniger als 4 beträgt. Damit ist der Algorithmus beendet.
Erste Iterationen:
Ein COBOL-Beispiel:
quelle
Hier ist eine elegante, generische Implementierung in Scala, wie unter 99 Scala-Probleme beschrieben .
quelle
Wenn Sie die SQL-Syntax verwenden können, z. B. wenn Sie mit LINQ auf Felder einer Struktur oder eines Arrays zugreifen oder direkt auf eine Datenbank mit einer Tabelle namens "Alphabet" mit nur einem Zeichenfeld "Letter" zugreifen, können Sie Folgendes anpassen Code:
Dies gibt alle Kombinationen von 3 Buchstaben zurück, ungeachtet der Anzahl der Buchstaben in der Tabelle "Alphabet" (es können 3, 8, 10, 27 usw. sein).
Wenn Sie nur Permutationen und keine Kombinationen wünschen (dh "ACB" und "ABC" sollen unterschiedlich sein und nicht nur einmal angezeigt werden), löschen Sie einfach die letzte Zeile (die UND-Zeile) und fertig.
Nachbearbeitung: Nachdem ich die Frage erneut gelesen habe, stelle ich fest, dass der allgemeine Algorithmus erforderlich ist , nicht nur ein spezifischer für den Fall der Auswahl von 3 Elementen. Die Antwort von Adam Hughes ist vollständig, leider kann ich sie (noch) nicht abstimmen. Diese Antwort ist einfach, funktioniert aber nur, wenn Sie genau 3 Elemente möchten.
quelle
Eine weitere C # -Version mit verzögerter Generierung der Kombinationsindizes. Diese Version verwaltet ein einzelnes Array von Indizes, um eine Zuordnung zwischen der Liste aller Werte und den Werten für die aktuelle Kombination zu definieren, dh verwendet während der gesamten Laufzeit ständig O (k) zusätzlichen Speicherplatz. Der Code generiert einzelne Kombinationen, einschließlich der ersten, in O (k) -Zeit.
Testcode:
Ausgabe:
quelle
c b a
was sie nicht enthält.https://gist.github.com/3118596
Es gibt eine Implementierung für JavaScript. Es hat Funktionen, um k-Kombinationen und alle Kombinationen eines Arrays von beliebigen Objekten zu erhalten. Beispiele:
quelle
Hier haben Sie eine faul evaluierte Version dieses in C # codierten Algorithmus:
Und Testteil:
Hoffe das hilft dir!
quelle
Ich hatte einen Permutationsalgorithmus, den ich für Project Euler in Python verwendet habe:
Wenn
Sie sollten alle Kombinationen haben, die Sie brauchen, ohne Wiederholung, brauchen Sie sie?
Es ist ein Generator, also verwenden Sie ihn in etwa so:
quelle
quelle
Clojure-Version:
quelle
Nehmen wir an, Ihre Buchstabenreihe sieht folgendermaßen aus: "ABCDEFGH". Sie haben drei Indizes (i, j, k), die angeben, welche Buchstaben Sie für das aktuelle Wort verwenden werden. Sie beginnen mit:
Zuerst variierst du k, also sieht der nächste Schritt so aus:
Wenn Sie das Ende erreicht haben, fahren Sie fort und variieren j und dann wieder k.
Sobald Sie j erreicht haben, beginnen Sie auch, i zu variieren.
Basierend auf https://stackoverflow.com/a/127898/2628125 , jedoch abstrakter für Zeiger jeder Größe.
quelle
Alles, was hier gesagt und getan wurde, ist der O'caml-Code dafür. Der Algorithmus ist aus dem Code ersichtlich.
quelle
Hier ist eine Methode, mit der Sie alle Kombinationen der angegebenen Größe aus einer Zeichenfolge mit zufälliger Länge erhalten. Ähnlich wie die Quinmars-Lösung, funktioniert jedoch für unterschiedliche Eingaben und k.
Der Code kann so geändert werden, dass er umbrochen wird, dh 'tupfen' von der Eingabe 'abcd' wk = 3.
Ausgabe für "abcde":
quelle
Ich habe hierfür eine Lösung in SQL Server 2005 erstellt und auf meiner Website veröffentlicht: http://www.jessemclain.com/downloads/code/sql/fn_GetMChooseNCombos.sql.htm
Hier ist ein Beispiel, um die Verwendung zu zeigen:
Ergebnisse:
quelle
Hier ist mein Vorschlag in C ++
Ich habe versucht, den Iteratortyp so wenig wie möglich einzuschränken, sodass diese Lösung nur einen Vorwärtsiterator voraussetzt und ein const_iterator sein kann. Dies sollte mit jedem Standardcontainer funktionieren. In Fällen, in denen Argumente keinen Sinn ergeben, wird std :: invalid_argumnent ausgelöst
quelle
Hier ist ein Code, den ich kürzlich in Java geschrieben habe und der die gesamte Kombination von "num" -Elementen aus "outOf" -Elementen berechnet und zurückgibt.
quelle
Eine prägnante Javascript-Lösung:
quelle
Algorithmus:
In C #:
Warum funktioniert es?
Es gibt eine Bijektion zwischen den Teilmengen einer n-Elementmenge und n-Bit-Sequenzen.
Das heißt, wir können herausfinden, wie viele Teilmengen es gibt, indem wir Sequenzen zählen.
Beispielsweise können die folgenden vier Elemente durch {0,1} X {0, 1} X {0, 1} X {0, 1} (oder 2 ^ 4) verschiedene Sequenzen dargestellt werden.
Also müssen wir nur von 1 bis 2 ^ n zählen, um alle Kombinationen zu finden.(Wir ignorieren die leere Menge.) Als nächstes übersetzen Sie die Ziffern in ihre binäre Darstellung. Ersetzen Sie dann 'on'-Bits durch Elemente Ihres Sets.
Wenn Sie nur k Elementergebnisse wünschen, drucken Sie nur, wenn k Bits aktiviert sind.
(Wenn Sie alle Teilmengen anstelle von Teilmengen mit k Länge möchten, entfernen Sie den Teil cnt / kElement.)
(Zum Beweis siehe MIT kostenlose Kursunterlagen Mathematik für Informatik, Lehman et al., Abschnitt 11.2.2. Https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics- für-Informatik-Herbst-2010 / Lesungen / )
quelle
kurzer Python-Code, der Indexpositionen ergibt
quelle
Ich habe eine Klasse geschrieben, die allgemeine Funktionen für die Arbeit mit dem Binomialkoeffizienten behandelt. Dies ist die Art von Problem, unter die Ihr Problem fällt. Es führt die folgenden Aufgaben aus:
Gibt alle K-Indizes in einem schönen Format für jedes N aus. Wählen Sie K in eine Datei. Die K-Indizes können durch aussagekräftigere Zeichenfolgen oder Buchstaben ersetzt werden. Diese Methode macht die Lösung dieser Art von Problem ziemlich trivial.
Konvertiert die K-Indizes in den richtigen Index eines Eintrags in der sortierten Binomialkoeffiziententabelle. Diese Technik ist viel schneller als ältere veröffentlichte Techniken, die auf Iteration beruhen. Dazu wird eine mathematische Eigenschaft verwendet, die Pascals Dreieck innewohnt. Mein Papier spricht darüber. Ich glaube, ich bin der erste, der diese Technik entdeckt und veröffentlicht, aber ich könnte mich irren.
Konvertiert den Index in einer sortierten Binomialkoeffiziententabelle in die entsprechenden K-Indizes.
Verwendet die Mark Dominus- Methode zur Berechnung des Binomialkoeffizienten, der viel weniger wahrscheinlich überläuft und mit größeren Zahlen arbeitet.
Die Klasse ist in .NET C # geschrieben und bietet eine Möglichkeit, die mit dem Problem verbundenen Objekte (falls vorhanden) mithilfe einer generischen Liste zu verwalten. Der Konstruktor dieser Klasse verwendet einen Bool-Wert namens InitTable, der bei true eine generische Liste für die zu verwaltenden Objekte erstellt. Wenn dieser Wert falsch ist, wird die Tabelle nicht erstellt. Die Tabelle muss nicht erstellt werden, um die 4 oben genannten Methoden auszuführen. Für den Zugriff auf die Tabelle werden Zugriffsmethoden bereitgestellt.
Es gibt eine zugehörige Testklasse, die zeigt, wie die Klasse und ihre Methoden verwendet werden. Es wurde ausgiebig mit 2 Fällen getestet und es sind keine Fehler bekannt.
Informationen zu dieser Klasse und zum Herunterladen des Codes finden Sie unter Tablizing The Binomial Coeffieicent .
Es sollte nicht schwer sein, diese Klasse in C ++ zu konvertieren.
quelle