文字列[] Z-アルゴリズム

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;
    }
  }
}

おすすめ

転載: www.cnblogs.com/yifusuyi/p/11462771.html