Z-アルゴリズム
アルゴリズム
仕事
テキスト文字列が与えられ\(S \)とパターン文字列の\(T \)を求めて、\(T \)のための(S \)\各サブサブ文字列のサフィックス文字列のための共通の接頭辞を。
制限事項
線形時間的複雑さは必要とされています
溶液
セット\(X-は\)文字列に次の式であり、\(x_u \)代表\(X- \)の\(U \)文字、\(X_ {U \ V} SIM \)の代表\ (X \)から\(U \)プレー\(V \)文字列の末尾を。
セット\(N- = | S |、〜M = | T | \) 。
走査の下降長さに考慮\(S \)接尾文字列、電流が必要提供\(S_ {iはシムを\ n } \) と(T \)\共通プレフィックスストリング、K FORALL \を(\ \ [1,2〜I)において 、〜S_ {K \シムのN} \) の回答が完了計算されます。
前の計算で設定し、マッチング\(S \)最初の時間のための最も遠い\(P \)倍、すなわち\(P + ans_p \)全部で\(K + ans_k \)最大設定\を(Q ans_pのp + = \) 。もちろんそこに\(P-<私は\) 。
まず、それが取ることができる\(Q \ GEQ I \) 。\(Q <I \)場合について説明します。
セット\(J = I -のP + 1 \) 、見つけることは困難ではない\(S_I T_J = \) 、すなわち\(J \)がされている(S_I \)を\マッチング位置に対応します。
需要はそれほどあり、共通のプレフィックス文字列であるため、
\ [S_ {P \ SIM Q = T_ {1} \} ans_p \はい]
補助変数のセットを導入し、設定\を(next_j \)の\(T_ {J \シムM } \) と\(T \)最長の共通接頭サブストリングの長さです。
定義により、そこに
\ [T_ {J \ SIM J + next_j} = T_ {1 \ SIM next_j} \]
2つのケースが議論しました。
前者の場合、\(J + next_j <Q \) 、すなわち\(T_ {J \ SIM J + next_j} \) されている\(S_ {P \シムのQ } \) 文字列、従って
\ [T_ {J \ SIM J + next_j} = S_ {iはnext_jを+ SIM \} \]
そしてため\(T_ {J \ J + next_j SIM T_ {} = 1 \ SIM next_j} \) (実証されている)、置換等量与えます
\ [S_ {私はnext_jを+ SIM \} = T_ {1 \ SIM next_j} \]
以下のための\(S_I + next_j +。1 \) 、に等しくないことを証明するために必要とすることができる(T_ {next_j + 1} \)\、さもなければ起因\(T_ {J + next_j + 1} \) のまま\(S_ { SIM Q \ P} \)の文字列の、\(T_ {J} = + next_j +。1 1 + next_j T_ {} \)、その\(next_j \)矛盾をサブストリング最長の共通のプレフィックスです。
したがって、この場合には、答えは\(next_j \)を。
後者の場合、\(J + next_j GEQ Q \ \) 、すなわち\(T_ {J \ SIM J + next_j} \) 不足はい\(S_ {P \シムのQ } \) 文字列、従って
まず、第1の場合に同じ証明方法証明することができる({。} 1 \ SIM Q I \ SIM = T_ {Q - I. 1} S_の+ \)\を、すなわち\(Q \)と前の文字であってもよい\ (T \)完全に一致する、とのために\(q個\)続く文字、我々は暴力と(T \)\試合、更新中\(のp \)と\(q個\)場所。
以下のために\(Q <I \)の場合、明らかに\(Qは= I - 。1 \)は、直接的な暴力が一致し続けています。
時間の複雑さを考慮してください。
暴力マッチングのリンクを取り除くために、残りの部分は明らかに、単一のです\(O(1)\)完成されているため、この部分の複雑さは線形です。
すべての試合の暴力ができるようになります考えてみましょう(q個\)\右に、そのシングルマッチ暴力がある一方で暴力的な試合の数は、線形である\(O(1)\) 、そのアルゴリズムの時間計算量が線形。
考えてみましょう(次\)\算出した配列:我々は、これはテキスト文字列に対応が可能ことがわかった\(S = T \) 、唯一の前処理が必要です\(next_1を\)と\(next_2を\)から見つけることができます\(next_3 \)必要な計算、以来\(次回\)の値が以前に計算されていますが。
サンプル
[P5410] [テンプレート] KMPを拡張します
説明
テキスト文字列が与えられ\(S \)とパターン文字列の\(T \)を求めて、\(T \)のための(S \)\各サブサブ文字列のサフィックス文字列のための共通の接頭辞を。そして、出力\(T \)接尾文字列と各\(T \)共通のプレフィックスのサブストリングの長さ。
制限事項
文字列の長さは超えていない\(10 ^ 5 \を)
溶液
潘タイトルを禁止。アルゴリズムは比較的実装の詳細を食べているかどうか、注意が倍のプラス同数未満の比較的大きいはずです。取ることを忘れないでください
コード
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 100005;
int nxt[maxn];
char S[maxn], T[maxn];
void Z_algorithm(const char *const A, const char *const B, const int x, const int y, const bool pt);
int main() {
freopen("1.in", "r", stdin);
scanf("%s\n%s", S + 1, T + 1);
int x = strlen(S + 1), y = strlen(T + 1);
nxt[1] = y;
Z_algorithm(T, T, y, y, false);
for (int i = 1; i <= y; ++i) {
qw(nxt[i], i == y ? '\n' : ' ', true);
}
Z_algorithm(S, T, x, y, true);
putchar('\n');
return 0;
}
void Z_algorithm(const char *const A, const char *const B, const int x, const int y, const bool pt) {
int p = 0, q = 1;
if (!pt) {
while ((q < x) && (A[q] == A[q + 1])) ++q;
nxt[p = 2] = q - 1;
q = std::max(q, 2);
} else {
while ((q <= x) && (q <= y) && (A[q] == B[q])) ++q;
p = 1;
qw(--q, ' ', true);
}
for (int i = pt ? 2 : 3, _ans; i <= x; ++i) {
int a = i - p + 1;
int len = nxt[a];
if ((i + len - 1) >= q) {
_ans = std::max(0, q - i + 1);
while ((q < x) && (_ans < y) && (A[q+1] == B[_ans+1])) {
++_ans; ++q;
}
q = std::max(p = i, q);
} else {
_ans = len;
}
if (pt) {
qw(_ans, ' ', true);
} else {
nxt[i] = _ans;
}
}
}