Anzahl der unterschiedlichen Teilzeichenfolgen im String innerhalb des Bereichs

7

Wenn der String Länge , kann das Ermitteln der Anzahl unterschiedlicher Teilzeichenfolgen in linearer Zeit unter Verwendung eines LCP-Arrays erfolgen. Anstatt nach der Anzahl der eindeutigen Teilzeichenfolgen in der gesamten Zeichenfolge fragen, fragt die Abfrage mit der Indizierung wobei nach der Anzahl der unterschiedlichen Teilzeichenfolgen innerhalb des angegebenen für die Zeichenfolge .SnSq(i,j)0ij<nS[i..j]

Mein Ansatz besteht darin, auf jede Abfrage eine lineare Zeitkonstruktion des LCP-Arrays anzuwenden. Es ergibt die Komplexität . Die Anzahl der Abfragen kann auf die Reihenfolge erhöht werden. also alle Abfragen beantworten, wird .O(|q|n)nO(n2)

Kann es besser gemacht werden als die lineare Zeit für jede Abfrage?

Wenn ein Prozess-Teilstring eines Strings, für den wir bereits ein Suffix-Array, einen Suffix-Baum oder ein lcp-Array haben, im Allgemeinen nicht mehr relevant ist und erneut von Grund auf neu erstellt werden muss?

Mechsoul
quelle
Die Größe der Eingabe und Ausgabe scheint natürliche Untergrenzen zu sein.
Raphael
1
Ich habe keine Zeit, darüber nachzudenken, aber es ist Standard, Segmentbäume aus diesen komplexen Strukturen zu erstellen (in der Wettbewerbsprogrammierung). Vielleicht ist dies bei Suffix-Arrays / Bäumen / etc. Der Fall. Sie müssen nur klug sein, um eine schnelle "Kombinations" -Operation zu definieren (die für einen Vaterknoten mit seinen Kindern verwendet wird oder am Ende, um die Ergebnisse aller Blätter zu kombinieren, die Ihr Intervall abdecken).
Md5
Die Anzahl der Abfragen ist die Anzahl der geordneten Paare die , daher sollte die Komplexitäti,j(n(n+1))/2O(n3)
user11171
@ md5 Ich glaube nicht, dass eine auf Segmentbäumen (oder Fenwick-Bäumen) basierende Lösung funktioniert, da der Anzahl der Teilzeichenfolgen die additive Inverse fehlt.
user11171

Antworten:

0

Die Frage motiviert nicht dazu, dass die Anzahl der Abfragen , was ein willkürlich schlechtester Fall zu sein scheint, da die Anzahl der eindeutigen möglichen Abfragen die Anzahl der geordneten Paare und damit .O(n)O(n2)

Hier sind zwei verschiedene Lösungen mit besserer Zeitkomplexität für den Fall basierend auf (impliziten) Suffixbäumen, die schrittweise mit dem Ukkonen-Algorithmus erstellt wurden . Beide Lösungen basieren auf der Vorverarbeitung und haben die Komplexität wobei die Menge der Abfragen ist. Die zweite Lösung wird in wenn alle Abfragen dieselbe Breite haben.O(n2)O(n2+|Q|)QO(n+|Q|)

Lösung 1 - Verarbeiten Sie alle eindeutigen Abfragen vor

Iterate über die Suffixe von . für jedes Suffix den Suffixbaum von mit dem Ukkonen-Algorithmus. Speichern Sie nach der Aktualisierung von auf den aktuellen Suffixbaum die Baumgröße in einer Matrix an Position . Eine Abfrage nach dem Bereich wird vom Matrixelement bei beantwortet .SSi=S[i..n]Sij(i,i+j1)[x,y](x,y)

Die Suffixbaumgröße kann zusammen mit dem Suffixbaum gespeichert und bei jedem Schritt in konstanter Zeit aktualisiert werden, indem die Aktualisierungsprozedur im Ukkonen-Algorithmus geändert wird. Mit jedem Update erhöht sich die Größe um die aktuelle Anzahl der Blätter.

Lösung 2 - Verarbeiten Sie eindeutige Abfragebreiten vor

Diese Lösung ist schwieriger zu implementieren, erfordert jedoch weniger Vorverarbeitungsarbeit, wenn nur wenige Abfragebreiten vorhanden sind. Die Vorverarbeitung benötigt Zeit, wenn nur eine Abfragebreite vorhanden ist.O(n)

Verwenden Sie für jede Abfragebreite ein Schiebefenster mit der Breite und erstellen Sie schrittweise einen Suffixbaum. Entfernen Sie das Suffix ab einem Zeichen links vom Fenster, indem Sie das längste Suffix aus dem Baum entfernen. Bei jedem Schritt entspricht die aktuelle Anzahl der Teilzeichenfolgen innerhalb des Schiebefensters der Baumgröße.ww

Alle Anfragen können dann unter Verwendung der Ergebnisse der Vorberechnung in linearer Zeit beantwortet werden.

Hinweis: Das Entfernen des längsten Suffix kann durch Entfernen des ältesten Blattes des Suffixbaums erfolgen. Die korrekte Implementierung ist nicht einfach.

user11171
quelle
Dies scheint ein bisschen anders zu sein. Die Aufgabe besteht nicht darin, alle möglichen -Anfragen zu beantworten, sondern einige gegebene Anfragen zu beantworten . O(n2)q
Gassa
Ich beantwortete die Frage für den allgemeinen Fall, um den es bei der Frage ging. In dem speziellen Fall, in dem die Anzahl der Abfragen gering ist, würde die vom Fragesteller vorgeschlagene Lösung in der Praxis schneller ablaufen. Die Anzahl der Ausgaben einer gültigen Lösung ist mit der Größe (ohne Berücksichtigung doppelter Abfragen). Daher muss jede mögliche Lösung in oder langsamer ausgeführt werden. Meine vorgeschlagene Lösung benötigt Zeit für die Vorverarbeitung, und dann kann jede Anfrage in konstanter Zeit beantwortet werden. qO(n2)O(n2)O(n2)
user11171
Auch hier ist ein Parameter. Die Frage wird in der Anzahl von Abfragen explizit interessiert wobei , nicht noch . Die Antwort für Abfragen hat die Größe die nicht . qqΘ(n)Θ(1)Θ(n2)qΘ(q)Θ(n2)
Gassa
Warum sollte die Anzahl der Abfragen in der Größenordnung von ? Es scheint eine willkürliche Bedingung zu sein, wenn nicht ein Versehen des Autors. n
user11171
Die gesamte Problemstellung ist in etwa gleich willkürlich. So sieht jedoch ein typisches Datenstrukturproblem in der Wettbewerbsprogrammierung aus, so dass es unwahrscheinlich ist, dass das OP nach Abfragen sucht. Ich würde wetten und sind unabhängig Parameter von zu oder so, und die Frist ist ein paar Sekunden, so dass sich eine Lösungszeiten, aber etwas besser wie nicht. n2nq1100000O(nq)O(nq)
Gassa
0

Es gibt eine Offline-Lösung .O(nn+|Q|n)

  1. Sortieren Sie die Elemente von in aufsteigender Reihenfolge von .(i,j)Qj
  2. Verteilen Sie sie in Buckets, sodass in die Bucket-Nummer .n(i,j)in
  3. Erstellen Sie für jeden Bucket, der bei beginnt, und jede Abfrage darin einen Suffixbaum für .b(i,j)S[b,j]
  4. Entfernen Sie für jede Abfrage in einem Bucket redundante Zeichen von links und melden Sie die Antwort.

Schritt 3 nimmt für jeden Bucket, da wir den Ukkonen-Algorithmus verwenden und in aufsteigender Reihenfolge abläuft .O(n)j

Schritt 4 benötigt für jede Abfrage, da das Entfernen der längsten Suffixe von aus dem Baum . Beachten Sie, dass Sie eine Indirektionsebene verwenden können, um Änderungen am ursprünglichen Suffixbaum zu vermeiden.O(n)nO(n)

Dmitri Urbanowicz
quelle
Die Anzahl der unterschiedlichen Teilzeichenfolgen ist die Anzahl der Pfade im Suffixbaum, die an der Wurzel beginnen und an einem Knoten enden, unter dem sich nur ein einziges Blatt befindet. Richtig? Speichern Sie diese Pfadzahlen explizit in den Notizen? Wenn ja, wie aktualisieren Sie dann die Dinge, wenn Sie das erste Zeichen in O (1) -Zeit entfernen? Es können bis zu von ihnen vorhanden sein (in dem Fall, in dem das erste Zeichen innerhalb des Blocks eindeutig ist). Wenn nicht, wie berechnen Sie sie im laufenden Betrieb? n
j_random_hacker
@j_random_hacker Der Algorithmus von Ukkonen erstellt einen sogenannten impliziten Suffixbaum. Die Anzahl der unterschiedlichen Teilzeichenfolgen ist nur die Summe der Kantenlängen (dh der Größe des entsprechenden Versuchs).
Dmitri Urbanowicz