Guten Algorithmus und Datenstruktur für das suchen nach Wörtern mit fehlenden Buchstaben?
so muss ich schreiben, ein effizienter Algorithmus für das suchen nach Wörtern mit fehlenden Buchstaben in einem Wörterbuch und ich will, dass die Menge der möglichen Worte.
Zum Beispiel, wenn ich in th??e, ich könnte wieder diese, diese, Thema gibt.etc.
Ich Frage mich, ob jemand vorschlagen kann, einige Datenstrukturen Algorithmus ich verwenden soll.
Dank!
EDIT: EIN Trie ist auch Raum ineffizient und würde es zu langsam. Weitere Ideen, änderungen?
UPDATE: Es wird bis zu ZWEI Fragezeichen und wenn zwei Fragezeichen auftreten, Sie werden auftreten, in der Reihenfolge.
Derzeit bin ich mit 3 hash-Tabellen für die wenn es ist eine exakte übereinstimmung, 1 Fragezeichen, und 2 Fragezeichen.
Gegeben ein Wörterbuch, das ich hash-alle möglichen Worte. Zum Beispiel, wenn ich das Wort WORT. Ich hash-WORT ?ORD, W?RD, WO?D, WOR?, ??RD, W??D, WO??. in das Wörterbuch. Dann benutze ich eine link-Liste zu verknüpfen, die Kollisionen zusammen. Also sagen wir, hash(W?RD) = hash(STR?NG) = 17. hashtab(17) Punkt-zu-WORD-und WORD-Punkte-zu-STRING, weil es eine verknüpfte Liste.
Timing auf die Durchschnittliche lookup eines Wortes ist etwa 2e-6s. Ich bin auf der Suche, besser zu machen, vorzugsweise in der Größenordnung von 1e-9.
EDIT: ich habe nicht sah das problem wieder, aber es dauerte 0,5 Sekunden für 3m-Einträge Einfüge, und es dauerte 4 Sekunden für 3m-lookup-Einträge.
Dank!
- Warum bist du nicht verwandelt diese in reguläre Ausdrücke und suchen? Was Versprechen Sie sich? Welche Erwartungen haben Sie? Welche Einschränkungen haben Sie?
- Wie schnell würden reguläre Ausdrücke werden? Ich weiß, was Sie sind, aber ich weiß nicht, wie Sie tatsächlich funktioniert. Ich kann nur traverse durch das gesamte Wörterbuch, aber das wäre Theta(N). Ich Frage mich, ob ich besser machen kann.
- Was bedeutet die Struktur des Wörterbuchs Aussehen?
- Jetzt ist es nur eine text-Datei mit allen Wörtern in alphabetischer Reihenfolge aufgelistet.
- Aktualisieren Sie die Frage. Bitte nicht kommentieren, eine Frage, die Sie besitzen. Sie eigenen in Frage. Sie können Sie aktualisieren, um alle Informationen enthalten. Bitte aktualisieren Sie die Frage.
- wie viele Wörter im Wörterbuch? was ist der Bereich der Längen? was alphabet verwendet wird?
- Warum genau würde eine space-ineffizient trie zu langsam? Rechnen Sie mit einer Ladung mehr Daten als Verfügbarer Speicher und schafft so viele Seitenfehler?
- Es ist das Englisch-Wörterbuch, das zwischen 200 - 500k Wörter
- Es klingt wie die Lösung, die Sie Hinzugefügt haben, die Frage ist äquivalent zu Anna ' s ersten Vorschlag (der hash), außer, dass Sie können unerwünschte Kollisionen. Wenn Sie wechseln Sie einfach zu Ihrem Vorschlag, den Sie verwenden werden, über die gleiche Menge an Speicher (also viele), aber Sie nicht haben, um zu überprüfen, die gesamte hash-Eimer für Kollisionen jeder Zeit, die Sie viel schneller.
- 1e-9 Sekunde pro Suche ist ein Milliarden Suchanfragen pro Sekunde. Der Computer in der Regel über die Uhren im Bereich von 1-3 Milliarden Takte pro Sekunde. Also selbst wenn man das pipelining zu berücksichtigen, und vorausgesetzt, keine Schleifen, das ist kaum realistisch.
- Sind Sie zufällig machen ein scrabble AI? (Da gibt es maximal 2 Leerzeichen im Spiel...)
- aber die Frage sagt die Rohlinge müssen benachbart sein, das ist nicht wahr, in Scrabble.
- 1e-9 ist einer Nanosekunde - das ist ungefähr so viel Zeit wie es dauert, einen normalen PC um zwei zahlen zu addieren. Es ist nichts falsch mit Ihrem Algorithmus, was Sie brauchen, ist ein super-computer.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube in diesem Fall ist es am besten, nur verwenden Sie eine flache Datei, wo jedes Wort steht in einer Zeile. Mit diesem können Sie bequem nutzen die Leistung eines regulären Ausdrucks suchen, ist hoch optimiert und wird wahrscheinlich schlagen jede Daten-Struktur, die Sie entwickeln können, sich selbst für dieses problem.
Lösung #1: Die Verwendung Von Regex
Dieser arbeitet Ruby-code für dieses problem:
Die Datei
wordlist.txt
enthält 45425 Worte (Download hier). Die Ausgabe des Programms für die Abfrage?r?te
ist:So dauert es nur 37 Millisekunden zu Lesen, ohne die ganze Datei zu finden, die alle Spiele drin. Und es skaliert sehr gut für alle Arten von Abfrage-Muster, auch dort, wo ein Trie ist sehr langsam:
Abfrage
????????????????e
Abfrage
?h?a?r?c?l?
Sieht dies schnell genug für mich.
Lösung #2: Regex mit Vorbereiteten Daten
Wenn Sie möchten, um noch schneller zu gehen, können Sie teilen Sie die Wortliste in strings, die Wörter enthalten, von gleicher Länge und nur die Suche die richtige ist, basierend auf Ihrer Abfrage Länge. Ersetzen Sie die letzten 5 Linien mit diesem code:
Erstellen der Daten-Struktur erfolgt nun über 0,4 sec, aber alle Abfragen sind etwa 10 mal schneller (je nach der Anzahl der Wörter mit Länge):
?r?te
0.001112 sec?h?a?r?c?l?
0.000852 sec????????????????e
0.000169 secLösung #3: Eine Große Hashtable (Aktualisierten Anforderungen)
Da haben Sie verändert Ihren Anforderungen können Sie problemlos erweitern, auf Ihre Idee zu nutzen, nur eine große Hash-Tabelle, die enthält alle vorberechneten Ergebnisse. Aber anstatt zu arbeiten, um die Kollisionen selbst könnten Sie verlassen sich auf die Leistung eines ordnungsgemäß umgesetzt hashtable.
Hier erstellen Sie eine große Hash-Tabelle, wo jede mögliche Abfrage maps, um eine Liste der Ergebnisse:
Ausgabe
Die query-performance ist O(1), es ist nur ein lookup in der Hashtabelle. Die Zeit, 2.0 e-05 ist wahrscheinlich unten der timer ist Präzision. Wenn es läuft 1000 mal, ich bekomme durchschnittlich 1.958 e-6 Sekunden pro Abfrage. Um es zu bekommen schneller, ich würde wechseln Sie zu C++ und verwenden Sie die Google Sparse Hash die ist extrem Speicher-effizient und schnell.
Lösung #4: Holen Sie Wirklich Ernst
Alle oben genannten Lösungen arbeiten und sollte gut genug für viele Anwendungsfälle. Wenn Sie wirklich wollen, ernst zu erhalten, und haben viel freie Zeit auf Ihre Hände, Lesen Sie einige gute Papiere:
Angesichts der aktuellen Einschränkungen:
Habe ich zwei praktikable Lösungen für Sie:
Die schnelle Lösung: HASH
Können Sie ein hash-welche Tasten sind Ihre Wörter mit bis zu zwei '?', und die Werte werden in einer Liste passende Worte. Dieser hash wird mit rund 100,000 + 100,000*6 + 100,000*5 = 1,200,000 Einträge (wenn Sie 2 Fragezeichen, Sie brauchen nur den Ort zu finden, der erste...). Jeder Eintrag speichert eine Liste von Wörtern, oder eine Liste von Zeigern auf die vorhandenen Wörter. Wenn Sie speichern eine Liste von Zeigern, und wir gehen davon aus, dass es im Durchschnitt weniger als 20 Wörter matching jedes Wort mit zwei '?', dann wird der zusätzliche Speicher ist kleiner als 20 * 1.200.000 werden = 24.000.000 ist.
Wenn jeder Zeigergröße 4 bytes, dann der Speicherbedarf ist hier (24.000.000 ist+1.200.000 werden)*4 bytes = 100,800,000 Byte ~= 96 mega-Byte.
Fazit dieser Lösung:
Hinweis: wenn Sie möchten, verwenden Sie einen hash, der eine kleinere Größe, die Sie können, aber dann ist es besser zu sparen, eine ausgeglichene Suchbaum, in dem jeder Eintrag statt einer verknüpften Liste, für eine bessere Leistung.
Die Raum-versierte, aber immer noch sehr schnell-Lösung: TRIE variation
Diese Lösung verwendet die folgende Beobachtung:
Die Suche im trie suchen würde, an der Länge des Wortes, und für die letzten paar Buchstaben, eine DFS-Traversierung bringen würde, alle Endungen.
Sehr schnell, und sehr Speicher-versierte Lösung.
So können nutzen diese Beobachtung, um etwas zu bauen, zu arbeiten, genau wie diese.
Kann man darüber nachdenken, jedes Wort, das Sie in dem Wörterbuch, wie ein Wort endet mit @ (oder jedes andere symbol, das nicht vorhanden ist in deinem Wörterbuch).
So ist das Wort 'space' wäre 'space@'.
Nun, wenn Sie drehen Sie jedes der Wörter, die mit dem ' @ ' - Zeichen, erhalten Sie die folgende:
(kein @ als ersten Buchstaben).
Wenn Sie alle diese Varianten in einem TRIE, können Sie problemlos das Wort finden Sie suchen bei der Länge des Wortes, durch 'drehen' zu deinem Wort.
Beispiel:
Sie möchten herausfinden, alle Wörter, die fit 's??ce' (einer von Ihnen ist der Raum, der andere ist Scheibe).
Sie bauen das Wort: s??ce@, und drehen Sie es so, dass die ? Zeichen ist am Ende. d.h. 'ce@s -??'
Alle von der rotation Variationen gibt es in der Marina, und insbesondere 'ce@spa' (die mit * gekennzeichneten oben). Nachdem der Anfang gefunden ist - Sie müssen gehen über alle Fortsetzungen in die Länge zu, und speichern Sie Sie. Dann müssen Sie, um Sie zu drehen, wieder so, dass die @ ist der Letzte Brief, und walla - Sie haben alle Begriffe, die Sie gesucht haben!
Fazit dieser Lösung:
Speicherverbrauch:
Für jedes Wort, alle seine Rotationen erscheinen in der Marina. Durchschnittlich *6 von der Größe des Speichers gespeichert ist, in der trie. Die trie Größe *3 (nur geraten...) der Raum gespeichert drin. So die insgesamt notwendigen Raum für diese versuche ist 6*3*100,000 = ist 1.800.000 Wörter ~= 6.8 mega-Byte.
Zeit für jede Suche:
Zusammenfassend, es ist sehr sehr schnell, und hängt von der Wortlänge * kleine Konstante.
Zusammenfassend...
Die zweite Wahl, hat eine gute Zeit/Platz-Komplexität und wäre die beste option für Sie zu verwenden. Es gibt ein paar Probleme mit der zweiten Lösung (in diesem Fall möchten Sie vielleicht die Verwendung der ersten Lösung):
Mir dieses problem klingt wie eine gute Passform für eine Trie Datenstruktur. Geben Sie das gesamte Wörterbuch in Ihre versuche, und dann das Wort nachschlagen. Für einen fehlenden Buchstaben, die Sie haben würde, um zu versuchen, alle sub-versucht, das sollte relativ einfach mit einer rekursiven Ansatz.
BEARBEITEN: ich schrieb eine einfache Implementierung dieser in Ruby nur jetzt: http://gist.github.com/262667.
????????????????e
std::hash_map
-- ich bin nicht sicher, wie viele Redewendungen vorkommen, dass wäre aber. cs.bu.edu/teaching/c/tree/trie hat einen überblick darüber, wie zu schreiben versuche in C, die möglicherweise oder möglicherweise nicht werden, ein wenig näher an C++ als Ruby. @martinus: Cool, meine erste Gabel! 🙂Directed Acyclic Word Graph wäre die perfekte Datenstruktur für dieses problem. Es kombiniert die Effizienz eines trie (trie kann gesehen werden als ein Spezialfall der DAWG), aber viel mehr Platz effiziente. Typische DAWG nehmen Bruchteil der Größe, die nur-text-Datei mit dem Worte nehmen würde.
Aufzählen von Wörtern, die bestimmte Bedingungen erfüllen ist einfach und das gleiche wie in trie - Sie müssen durch den Graphen depth-first-Mode.
Annas zweite Lösung ist die inspiration für diese ein.
Laden Sie zuerst alle Worte ins Gedächtnis und teilen Sie das Wörterbuch, in Abschnitte basierend auf word-Länge.
Für jede Länge, machen n Kopien ein array von Zeigern auf die Worte. Sortieren Sie die einzelnen array so, dass die Zeichenfolgen geschaltet werden, um , wenn gedreht wird, indem eine bestimmte Anzahl von Buchstaben. Angenommen, die original-Liste von 5-Buchstaben-Wörter ist [Flugzeug -, Apfel -, Raum -, Zug -, fröhlich, stapeln, hacks]. Dann werden Ihre fünf arrays von Zeigern werden:
(Anstelle von Zeigern, die Sie verwenden können, ganze zahlen identifizieren die Wörter, wenn das spart Speicherplatz auf Ihrer Plattform.)
Suchen, Fragen Sie einfach, wie viel müssten Sie drehen Sie die Muster so, dass das Fragezeichen am Ende. Dann können Sie die binäre Suche in der entsprechenden Liste.
Wenn Sie brauchen, um zu finden, matches ??ppy, Sie hätte sich zu drehen, die durch 2 zu machen, ppy??. So suchen Sie in dem array, das ist in Ordnung, wenn gedreht wird durch 2 Buchstaben. Eine schnelle binäre Suche findet, dass "happy" ist das einzige Spiel.
Wenn Sie brauchen, um zu finden entspricht nach th??g, Sie hätte sich zu drehen, die durch 4 zu machen gth??. So suchen Sie in der Reihe 4, wo eine binäre Suche findet, dass es keine Spiele.
Dies funktioniert, egal wie viele Fragezeichen es gibt, solange Sie alle zusammen erscheinen.
Platzbedarf neben dem Wörterbuch selbst: Für Wörter der Länge N, das erfordert Platz für die (N-mal die Anzahl der Wörter der Länge N) Zeiger oder Ganzzahlen.
Zeit pro Suche: O(log n), wobei n die Anzahl der Wörter der entsprechenden Länge.
Implementierung in Python:
Auf meinem computer, das system-Wörterbuch ist von 909KB groß und nutzt dieses Programm über 3.2 MB Arbeitsspeicher zusätzlich zu dem, was es braucht, nur zum speichern der Wörter (Pointer sind 4 bytes). Für dieses Wörterbuch sind, könnten Sie schneiden, dass in der Hälfte durch Verwendung von 2-byte-Ganzzahlen anstelle von Zeigern, da es weniger als 216 Wörter jeder Länge.
Maße: Auf meinem Rechner
m.find("st??k")
läuft in 0.000032 Sekundenm.find("ov???low")
im 0.000034 Sekunden, undm.find("????????????????e")
im 0.000023 Sekunden.Durch das schreiben aus die binäre Suche anstelle der Verwendung
class RotatedArray
und diebisect
Bibliothek, ich habe die ersten zwei zahlen nach unten zu 0.000016 Sekunden: doppelt so schnell. Implementierung in C++ würde es noch schneller.?h?a?r?c?l?
.Als erstes benötigen wir eine Möglichkeit zum Vergleich der query-string mit einem bestimmten Eintrag. Nehmen wir an, eine Funktion mit regexes:
matches(query,trialstr)
.Einen O(n) Algorithmus wäre zu einfach verlaufen durch jeden Punkt der Liste (Wörterbuch vertreten sein werden als Liste in das Programm), Vergleich der einzelnen, um Ihre Abfrage-string.
Mit ein wenig pre-Berechnung, die Sie verbessern könnte dieses für eine große Anzahl von Abfragen durch den Bau einer zusätzlichen Liste der Wörter für jeden Buchstaben, so dass Ihr Wörterbuch Aussehen könnte:
Dies wäre jedoch nur von begrenztem nutzen, insbesondere, wenn Ihre query-string beginnt mit einem unbekannten Charakter. So können wir noch besser machen mit der Feststellung, wo Sie bei einem bestimmten Wort einen bestimmten Buchstaben liegt, generieren:
Wie Sie sehen können, ohne mit Indizes, Sie werden am Ende enorm die Erhöhung der Menge des benötigten Speicherplatzes - jedoch speziell ein Wörterbuch mit n Wörtern und Durchschnittliche Länge m benötigen nm2 Stauraum. Allerdings könnte man jetzt sehr schnell tun, Ihr Aussehen, bis man alle Wörter von jedem Satz, die mithalten können.
Die endgültige Optimierung (die Sie nutzen könnten, von der Fledermaus auf den naiven Ansatz) ist auch eine Trennung aller Wörter der gleichen Länge in separaten Läden, da Sie immer wissen, wie lange das Wort ist.
Diese version wäre O(kx), wo k die Nummer von bekannte Briefe in die Abfrage Wort, und x=x(n) ist die Zeit zu schauen, bis ein einzelnes Element in einem Wörterbuch der Länge n in Ihrer Umsetzung (in der Regel log(n).
Also mit einer endgültigen Wörterbuch wie:
Dann unser Algorithmus ist einfach:
Am Ende, der Satz
possiblewords
enthält all die passenden Buchstaben.Wenn Sie erzeugen alle möglichen Wörter, die dem Muster entsprechen (separate, arbte, arcte ... zryte, zrzte) und dann sehen Sie in einem binären Baum Darstellung des Wörterbuchs, die die durchschnittlichen Leistungsmerkmale O(e^N1 * log(N2)), wo N1 die Anzahl der Fragezeichen und N2 ist die Größe des Wörterbuchs. Scheint gut genug für mich, aber ich bin sicher, es ist möglich, um herauszufinden, einen besseren Algorithmus.
BEARBEITEN: Wenn Sie mehr als, sagen wir, drei Fragezeichen, haben Sie einen Blick auf Phil H ' s Antwort und seinem Brief Indizierung Ansatz.
Nehme an, Sie haben genügend Speicherplatz, man konnte bauen ein Riesen-hashmap, um die Antwort in konstanter Zeit. Hier ist ein kurzes Beispiel in python:
Können Sie einen Blick auf, wie Ihre getan in aspell. Sie werden aufgefordert Anregungen des richtige Wort für die falsch geschriebenen Wörter.
Bauen Sie ein hash-set von all den Worten. Zu finden passt, ersetzen Sie die Fragezeichen im Muster, bei dem jede mögliche Kombination von Buchstaben. Wenn es zwei Fragezeichen, eine Abfrage besteht aus 262 = 676 schnelle, Konstante erwartete-Zeit-hash-table-lookups.
Diese verbraucht weniger Speicher als meine andere Antwort, aber wird es exponentiell langsamer, da Sie mehr Fragezeichen.
Wenn 80-90% Genauigkeit ist akzeptabel, könnten Sie verwalten, mit Peter Norvig ist Rechtschreibprüfung. Die Umsetzung ist klein und elegant.
Eine regex-basierte Lösung betrachten jeden möglichen Wert in Ihrem Wörterbuch. Wenn die Leistung ist die größte Einschränkung, ein index gebaut werden konnte, um ihn zu beschleunigen erheblich.
Könnten Sie beginnen mit einem index auf jedes Wort der Länge enthält einen index jeder index=Charakter entsprechenden Wort-Sätze. Für die Länge von 5 Wörtern, zum Beispiel
2=r : {write, wrote, drate, arete, arite}, 3=o : {wrote, float, group}
usw. Um die möglichen übereinstimmungen für die ursprüngliche Abfrage, sagen '?ro??', das Wort setzt wäre durchschnitten was in{wrote, group}
in diesem Fall.Dies ist unter der Annahme, dass das nur Platzhalter, wird ein einzelnes Zeichen, und dass die Wortlänge bekannt vor. Wenn diese ungültig sind Annahmen, kann ich nur empfehlen, n-Gramm-basierte text-matching, wie besprochen, in dieses Papier.
Die Daten-Struktur, die Sie wollen, ist aufgerufen, eine trie - siehe wikipedia-Artikel für eine kurze Zusammenfassung.
Ein trie ist ein Baum, der Struktur, wo sich die Pfade durch den Baum bilden die Menge aller Wörter, die Sie verschlüsseln wollen - jeder Knoten kann bis zu 26 Kinder, auf für jeden möglich, den Brief auf die nächste Zeichenposition. Siehe das Diagramm im wikipedia-Artikel, um zu sehen, was ich meine.
Haben Sie sich überlegt mit einem Ternäre Suche Baum?
Die lookup-Geschwindigkeit ist vergleichbar mit einem versuchten, aber es ist mehr Platz-effizient.
Habe ich implementiert diese Datenstruktur mehrere Male, und es ist eine ziemlich einfache Aufgabe in den meisten Sprachen.
Mein Erster Beitrag hatte einen Fehler, dass Jason fand es nicht gut funktionieren wenn ?? am Anfang war. Ich habe jetzt mir die zyklischen Verschiebungen von Anna..
Meine Lösung:
Die Einführung einer end-of-Wort-Zeichen (@) und speichern Sie alle zyklisch verschoben Worte in sortierten arrays!! Verwenden Sie eine sortierte array für jedes Wort der Länge. Bei der Suche nach "th??e -@", eine Verschiebung der saite zu verschieben ?-markiert bis zum Ende (Beschaffung e@th??) und wählen Sie das array, das Wörter der Länge 5 und eine binäre Suche nach dem ersten Wort, die nach der Zeichenfolge "e@th". Alle übrigen Wörter in dem array übereinstimmen, d.h., wir finden "e@thoo (thoose), e@thes (diese) usw.
Die Lösung ist Zeit-Komplexität von Log( N ), wobei N die Größe des Wörterbuchs, und es wird die Größe der Daten um einen Faktor von 6 oder so ( die Durchschnittliche Wortlänge)
Hier ist, wie ich es tun würde:
'?'
.TreeMap.higherKey(base)
undTreeMap.lowerKey(next(base))
zu finden, wird der Bereich innerhalb der Zeichenfolge zwischen die matches werden gefunden. (Dienext
Methode muss zur Berechnung der nächsten größeren Wort, um die Basis-Zeichenfolge mit der gleichen Anzahl oder weniger Zeichen; z.B.next("aa")
ist"ab"
,next("az")
ist"b"
.)Matcher.find()
zu suchen, die Teilstrings entsprechend zu dem Bereich.Schritte 1 und 2 sind vorher getan was eine Daten-Struktur mit der
O(NlogN)
Raum, woN
ist die Anzahl der Wörter.Dieser Ansatz verkommt zu einer brute-force-regex-Suche von das gesamte Wörterbuch, wenn die
'?'
erscheint in der ersten position, aber je weiter rechts es liegt, desto weniger übereinstimmende getan werden muss.BEARBEITEN:
Zur Verbesserung der performance in dem Fall, wo
'?'
ist das erste Zeichen, erstellen Sie eine sekundäre lookup-Tabelle, die Datensätze der start - /Ende-offsets der läuft von Worten, deren zweites Zeichen 'a', 'b', und so weiter. Dies kann verwendet werden, in dem Fall, wo die erste nicht-'?' ist der zweite Charakter. Sie können uns eine ähnliche Vorgehensweise für Fälle, in denen der erste nicht-'?' ist das Dritte Zeichen, der vierte Charakter und so weiter, aber Sie am Ende mit größeren und größeren Zahl von kleineren und kleinere Auflagen, und schließlich diese "Optimierung" wird unwirksam.Einen alternativen Ansatz, der erfordert deutlich mehr Platz, aber der ist schneller in den meisten Fällen ist die Vorbereitung der dictionary-Datenstruktur, wie Sie oben für alle Drehungen der Wörter im Wörterbuch. Zum Beispiel, die erste Drehung, die würde darin bestehen, alle Worte, 2 Zeichen oder mehr mit dem ersten Zeichen des Wortes verschoben, um das Ende des Wortes. Die zweite rotation wäre Worte mit 3 Zeichen oder mehr mit den ersten beiden Zeichen verschoben an das Ende, und so weiter. Dann führen Sie die Suche, suchen Sie nach dem längste Folge von nicht -'?' - Zeichen im Suchtext. Wenn der index des ersten Zeichens dieser Teilstring
N
verwenden Sie dieNth
rotation zu finden, das reicht, und die Suche in der N-TEN Drehung word-Liste.Eine faule Lösung ist, lassen Sie SQLite oder einem anderen DBMS, die Arbeit für Sie erledigen.
Einfach erstellen Sie eine in-memory-Datenbank, laden Sie Ihre Worte und ausführen, wählen Sie den LIKE-operator.
Zusammenfassung: Verwenden Sie zwei compact-binary-gesucht-Indizes, eines der Worte, und eine der Umgekehrt Worte. Der Raum kostet ist 2N Zeiger, die Indizes, fast alle Suchvorgänge sehr schnell gehen; der Schlimmste Fall "??e", ist immer noch anständig. Wenn Sie separate Tabellen für jedes Wort der Länge, das würde selbst dem schlimmsten Fall sehr schnell.
Details: Stephen C. geschrieben, eine gute Idee,: suchen Sie eine geordnete Wörterbuch zu finden, den Bereich, wo das Muster erscheinen kann. Dies hilft nicht, wenn das Muster startet mit einer wildcard. Sie könnten auch den index von word-Länge, aber hier ist eine andere Idee: hinzufügen eines geordneten index, der die Umgekehrt Wörterbuch; dann ein Muster bringt immer einen kleinen Bereich in entweder der vorwärts-index oder umgekehrter-Wort-index (da wir gerade gesagt, es gibt keine Muster, wie ?ABCD?). Die Worte selbst müssen nur einmal gespeichert, wobei die Einträge der beiden Strukturen zeigen auf den selben Worten, und die lookup-Verfahren können Sie entweder vorwärts oder rückwärts; aber die Verwendung von Python die built-in-binary-search-Funktion, die ich gemacht habe, zwei separate Zeichenfolgen-arrays stattdessen verschwenden Platz. (Ich bin mit einem sortierten array statt einem Baum, wie andere vorgeschlagen haben, da es Platz spart und geht mindestens genauso schnell.)
Code:
Tests: (Der code funktioniert auch für Muster, wie ?AB?D?, allerdings ohne die Geschwindigkeit zu garantieren.)
Effizienz: Diese Bedürfnisse 2N Zeiger plus den erforderlichen Speicherplatz zum speichern der Wörterbuch-word-text (die getunte version). Das worst-case-Zeit kommt auf das Muster"??e' die Blicke an 44062 Kandidaten in meinem 235k-word /usr/share/dict/words; aber fast alle Abfragen sind wesentlich schneller, wie 'h??lo " ein Blick auf 190, und die Indizierung zunächst auf Wort-Länge reduzieren würde '??e' fast zu nichts, wenn wir müssen. Jede Kandidaten-check geht schneller als die hashtable-lookups andere vorgeschlagen haben.
Ähnelt dem Rotationen-index Lösung, die verhindert, alle false-match-Kandidaten auf Kosten des Müssens über 10N Zeigern anstelle von 2N (angenommen, dass eine Durchschnittliche Wortlänge von etwa 10, wie in meiner /usr/share/dict/words).
Könnten Sie tun, ein einzelnes binary search pro Suche, anstelle von zwei, mit einem benutzerdefinierten such-Funktion sucht nach nieder-gebunden und high-gebunden zusammen (so der gemeinsame Teil der Suche nicht wiederholt).
Wenn Sie nur
?
wildcards, keine*
wildcards entsprechen, eine variable Anzahl von Zeichen, die Sie könnten versuchen, diese: Für jedes Zeichen index, bauen Sie ein Wörterbuch von Zeichen zu Wörtern. d.h., wenn die Worte schreiben, schrieb, drate, arete, arite, Ihrer dictionary-Struktur würde wie folgt Aussehen:Wenn Sie wollen, schauen
a?i??
Sie würden das set, das entspricht-Zeichen index 0 => 'a' {"arete", "arite"} und dem Satz, entspricht Zeichen, index 2 = 'i' => {"write", "arite"} und nehmen den Satz Kreuzung.Wenn Sie ernsthaft wollen, etwas in der Größenordnung von einer Milliarde Suchanfragen pro Sekunde (obwohl ich nicht davon träumen, warum jemand außerhalb von jemandem machen, der nächste grand-master-scrabble AI oder etwas für eine riesige web-service wollen, dass schnell), ich empfehle die Verwendung threading, um zu laichen [Anzahl der Kerne auf deine Maschine] threads + einem master-thread, dass die Delegierten die Arbeit auf alle threads. Wenden Sie dann die beste Lösung, die Sie bis jetzt gefunden habe und hoffe, dass Sie don ' T run out of memory.
Eine Idee, die ich hatte, ist, dass Sie beschleunigen einigen Fällen durch die Zubereitung in Scheiben geschnitten unten Wörterbücher per Brief, dann, wenn Sie wissen, die ersten Buchstaben der Auswahl, können Sie resort zu suchen in einem viel kleineren Heuhaufen.
Ein anderer Gedanke, den ich hatte, war, dass Sie versuchten, um brute-force etwas -- vielleicht Baue eine DB oder Liste oder so für scrabble?