Dwa słowa są
kwadratowo równoważne gdy możemy zamienić jedno w drugie wykonując ciąg (być może pusty) operacji zamiany podsłowa typu \(zz\) przez \(z\) lub podsłowa \(z\) przez \(zz\). Inaczej mówiąc definiujemy \(z \approx zz\) oraz \(x \approx y\) gdy można otrzymać \(x\) z \(y\) przez wielokrotne stosowanie \(z \to zz\) dla podsłów \(x\) lub \(y\). Na przykład słowa abac, aabaabaac i ababaabaabbabbaacc są kwadratowo równoważne.
Niech \(\Sigma(x)\) będzie zbiorem liter słowa \(x\). Zauważmy, że
$$x\approx y\ \Rightarrow \ \Sigma(x)=\Sigma(y)$$
Oznaczamy
$$\hat{x} = p \alpha \beta q, \quad p,\, q \in \Sigma(x)^*, \ \alpha,\, \beta \in \Sigma(x)$$
gdzie \(p\alpha\) to najkrótszy prefiks taki, że \(\Sigma(p\alpha)=\Sigma(x)\) oraz \(\beta q\) najkrótszy sufiks o tej samej własności. Zauważmy, że
$$\Sigma(p) = \Sigma(x) - \lbrace \alpha \rbrace$$
Teoretyczna charakteryzacja równoważności kwadratowej.
Następujący fakt (a dokładniej punkt 2) daje algorytm sprawdzania równoważności kwadratowej.
Przy pomocy lematu udowodnijmy twierdzenie główne.
Konstrukcja efektywnego algorytmu
Korzystając wprost z twierdzenia można skontruować wykładniczy algorytm sprawdzania równoważności kwadratowej dwóch słów \(x_1\) i \(x_2\). Jeśli alfabet \( \Sigma \) jest stosunkowo niewielki, to można nieco inaczej podejść do problemu. Będziemy identyfikowali podsłowa słów \(x_1\) i \(x_2\) z pewnymi klasami abstrakcji relacji równoważności kwadratowej. Dzięki temu, znając identyfikatory podsłów \(p_1\), \(p_2\), \(s_1\) i \(s_2\) oraz symbole \(\alpha_1\), \(\alpha_2\), \(\beta_1\) i \(\beta_2\) będziemy mogli w czasie stałym odpowiedzieć na pytanie o równoważność kwadratową całych słów.
Dla ustalenia uwagi przyjmijmy, że działamy tylko na jednym słowie \(w = x_1 \$ x_2\) o długości \(n\). Dzięki temu gdy określimy klasę abstrakcji prefiksu \(x_1\) i sufiksu \(x_2\), będziemy mogli od razu odpowiedzieć na pytanie o równoważność kwadratową. Zauważmy bowiem, że słowo \(w\) ma rozkład \( (p,\, \alpha,\, \beta,\, s) = (x_1,\, \$,\, \$,\, x_2) \). Jednakże aby znaleźć identyfikator klasy abstrakcji słów \(x_1\) oraz \(x_2\), musimy dla nich wykonać odpowiedni rozkład, dla tych rozkładów wykonać kolejne itd. Każdy "poziom" rozkładu powoduje zmniejszenie rozmiaru alfabetu o 1. Skonstruujemy zatem algorytm bottom-up, który w kolejnych fazach \(k = 1,\, 2,\ldots,\, \vert \Sigma \vert \) będzie obliczał klasy abstrakcji podsłów, składających się z alfabetu rozmiaru \(k\).
Aby nie tracić czasu na częste odszukiwanie rozkładu \(p\) i \(s\) oraz odpowiadających im identyfikatorów klas abstrakcji, potrzebne nam będą dwie tablice. Niech \(PREF_k[i]\) zawiera identyfikator klasy abstrakcji podsłowa \(w[i..j]\), gdzie \(j\) jest takie, że podsłowo \(w[i..j]\) składa się z dokładnie \(k\) różnych znaków, ale podsłowo \(w[i..j+1]\) składa się już z \(k + 1\) różnych znaków. Zauważmy, że wtedy dla pewnego podsłowa \(v = w[i..t]\), gdzie \(t > j\) podsłowo \(w[i..j]\) jest \(p\) z twierdzenia, a symbol \(w[j+1]\) jest \(\alpha\) (przy założeniu lokalnego ograniczenia alfabetu do \(k + 1\) znaków). Niech także \(SUF_k[i]\) zawiera identyfikator klasy abstrakcji podsłowa \(w[j..i]\), gdzie \(j\) definiujemy analogicznie.
Dla \(k = 1\) ustalamy \(PREF_k[i] := SUF_k[i] := \mathcal{I}(w[i])\) dla \(i = 1,\, 2, \ldots,\, n\), gdzie \(\mathcal{I}\) jest operatorem nadania unikalnego identyfikatora symbolom z alfabetu \(\Sigma\). Dla \(k > 1\) obliczamy \(PREF_k\) następująco:
- Dla każdego \(i = 1,\, 2 \ldots\) szukamy wartości \(j\) (z definicji \(PREF\)).
- Obliczamy \(PREF_k[i]\) jako identyfikator klasy abstrakcji słowa reprezentowanego przez trójkę \( (PREF_{k-1}[i],\, \mathcal{I}(w[j + 1]),\, SUF_{k-1}[j]) \).
Analogicznie obliczamy \(SUF_k\). Dla ustalonego \(k\) algorytm działa w czasie liniowym: wartości \(j\) przy obliczaniu \(PREF\) (odpowiednio \(SUF\)) tylko rosną (odpowiednio maleją), więc ich wyznaczanie można wykonać w czasie liniowym. Drugą część również można wykonać liniowo; generujemy trójki zgodnie z algorytmem, a następnie sortujemy je pozycyjnie i bloki takich samych trójek numerujemy unikalnym identyfikatorem.
Podsumowując, powyższy algorytm dowodzi następującego faktu.
Twierdzenie
Równoważność kwadratową dwu tekstów o sumarycznym rozmiarze \(n\) nad alfabetem \(k\)-elementowym można sprawdzić w czasie \(O(n\cdot k)\).