Ich habe ein ziemlich komplexes Suchproblem, das ich auf die folgende Beschreibung reduzieren konnte. Ich habe gegoogelt, aber keinen Algorithmus gefunden, der zu meinem Problem zu passen scheint. Insbesondere die Notwendigkeit, beliebige ganze Zahlen zu überspringen. Vielleicht kann mich hier jemand auf etwas hinweisen?
Nehmen Sie zum Beispiel eine Folge von ganzen Zahlen A (1 2 3 4)
Nehmen Sie verschiedene Folgen von ganzen Zahlen und testen Sie, ob eine davon mit A übereinstimmt.
- A enthält alle Ganzzahlen in der getesteten Sequenz
- Die Reihenfolge der ganzen Zahlen in der getesteten Sequenz ist in A gleich
- Wir kümmern uns nicht um Ganzzahlen in A, die nicht in der Testsequenz enthalten sind
- Wir wollen alle passenden Testsequenzen, nicht nur die ersten.
Ein Beispiel
A = (1 2 3 4)
B = (1 3)
C = (1 3 4)
D = (3 1)
E = (1 2 5)
B entspricht A
C entspricht A
D stimmt nicht mit A überein, da die Reihenfolge unterschiedlich ist
E stimmt nicht mit A überein, da es eine Ganzzahl enthält, die nicht in A enthalten ist
Ich hoffe, dass diese Erklärung klar genug ist. Ich habe es am besten geschafft, einen Baum der Testsequenzen zu erstellen und über A zu iterieren. Das Erfordernis, Ganzzahlen überspringen zu können, führt zu vielen erfolglosen Suchpfaden.
Vielen Dank
Wenn ich einige Vorschläge lese, habe ich das Gefühl, dass ich ein paar Punkte klarstellen muss, die ich zu vage gelassen habe.
Wiederholte Zahlen sind zulässig, was in der Tat sehr wichtig ist, da eine einzelne Testsequenz auf mehrere Arten mit A übereinstimmen kann
A = (1234356), B = (236), Übereinstimmungen könnten entweder -23 --- 6 oder -2--3-6 sein
Ich erwarte, dass es eine sehr große Anzahl von Testsequenzen gibt, mindestens zu Tausenden, und Sequenz A wird tendenziell eine maximale Länge von 20 haben. Daher wird es extrem ineffizient, einfach zu versuchen, jede Testsequenz einzeln durch Iterieren abzugleichen.
Entschuldigung, wenn das nicht klar war.
quelle
Antworten:
Hmm, ich kann mir zwei mögliche Algorithmen vorstellen: Einen linearen Scan durch die A- Sequenz oder das Erstellen eines Wörterbuchs mit einer zeitlich konstanten Suche der Indizes.
Wenn Sie viele mögliche Teilsequenzen B gegen eine einzelne größere Sequenz A testen , würde ich vorschlagen, dass Sie die Variante mit dem Wörterbuch verwenden.
Linearer Scan
Beschreibung
Wir pflegen einen Cursor für die Sequenz A . Dann wiederholen wir durch alle Elemente in der Subsequenz B . Für jeden Artikel bewegen wir den Cursor in A vorwärts, bis wir einen passenden Artikel gefunden haben. Wenn kein passendes Element gefunden wurde, ist B keine Untersequenz.
Dies läuft immer in O (seq.size) .
Pseudocode
Imperativer Stil:
Funktionsstil:
Beispielimplementierung (Perl):
Wörterbuch-Suche
Beschreibung
Wir ordnen die Elemente der Sequenz A ihren Indizes zu. Dann suchen wir geeignete Indizes für jedes Element in B , überspringen die zu kleinen Indizes und wählen den kleinstmöglichen Index als Untergrenze. Wenn keine Indizes gefunden werden, ist B keine Untersequenz.
Läuft in so etwas wie O (subseq.size · k) , wobei k beschreibt, wie viele doppelte Zahlen enthalten sind
seq
. Dazu ein O- Overhead (seq.size)Der Vorteil dieser Lösung besteht darin, dass eine negative Entscheidung viel schneller (bis hin zu einer konstanten Zeit) getroffen werden kann, wenn Sie den Aufwand für die Erstellung der Nachschlagetabelle bezahlt haben.
Pseudocode:
Imperativer Stil:
Funktionsstil:
Beispielimplementierung (Perl):
Dictionary-Lookup-Variante: Codierung als endliche Zustandsmaschine
Beschreibung
Wir können die algorithmische Komplexität weiter auf O (subseq.size) reduzieren, wenn wir mehr Speicher einsetzen. Anstatt Elemente ihren Indizes zuzuordnen, erstellen wir ein Diagramm, in dem jeder Knoten ein Element an seinem Index darstellt. Die Kanten zeigen mögliche Übergänge, zB hätte die Sequenz
a, b, a
die Kantena@1 → b@2, a@1 → a@3, b@2 → a@3
. Dieser Graph entspricht einer endlichen Zustandsmaschine.Während der Suche pflegen wir einen Cursor, der anfangs der erste Knoten des Baums ist. Wir gehen dann die Kante für jedes Element in der Unterliste B . Wenn keine solche Kante existiert, ist B keine Unterliste. Wenn der Cursor nach allen Elementen einen gültigen Knoten enthält, ist B eine Unterliste.
Pseudocode
Imperativer Stil:
Funktionsstil:
Beispielimplementierung (Perl):
quelle
study
funktioniert und ob die verwendeten Algorithmen hier eine praktische Anwendung finden könnten?study
hatte zuvor, ähnlich wie meine zweite Lösung, Nachschlagetabellen von Zeichen zu Position erstellt.Hier ist ein praktischer Ansatz, der "die harte Arbeit" des Implementierens Ihres eigenen Algorithmus vermeidet und auch "das Rad neu erfinden" vermeidet: Verwenden Sie eine reguläre Ausdrucksmaschine für das Problem.
Setzen Sie einfach alle Zahlen von A in eine Zeichenfolge und alle Zahlen von B in eine durch den regulären Ausdruck getrennte Zeichenfolge
(.*)
. Fügen Sie^
am Anfang und$
am Ende ein Zeichen hinzu . Lassen Sie dann Ihre Lieblingsmaschine für reguläre Ausdrücke nach allen Übereinstimmungen suchen. Zum Beispiel, wennA = (1234356), B = (236)
erstelle eine reg exp für B like
^(.*)2(.*)3(.*)6(.*)$
. Führen Sie nun eine globale reguläre Suche durch. Um herauszufinden, an welchen Positionen in A Ihre Subsequenz übereinstimmt, überprüfen Sie einfach die Länge der ersten 3 Submatches.Wenn Ihr ganzer Zahlenbereich von 0 bis 9 reicht, können Sie in Betracht ziehen, diese zuerst mit einzelnen Buchstaben zu codieren, damit dies funktioniert, oder Sie müssen die Idee mit einem Trennzeichen anpassen.
Natürlich hängt die Geschwindigkeit dieses Ansatzes stark von der Geschwindigkeit der von Ihnen verwendeten reg exp-Engine ab, aber es sind hochoptimierte Engines verfügbar, und ich denke, es wird schwierig sein, einen schnelleren Algorithmus "out of the box" zu implementieren. .
quelle
Dieser Algorithmus sollte sehr effizient sein, wenn die Länge und die Iteration der Sequenz effizient sind.
sequence
und je kürzer lagernsubsequence
sequence
.sequence
gleich der Zahl an der aktuellen Position vonsubsequence
sequence
eines weiterensubsequence
am Ende dessequence
quelle