Zアルゴリズム
Zアルゴリズムは、文字列マッチングのためのアルゴリズムです。このアルゴリズムの核心は、その\(Z \)アレイとの算出の方法。
(以下、添字コンベンション文字列\(1 \)が始まります)
\(\ BM Z \)アレイとZボックス
定義\(Zの\)配列:\(Z_は、{A、I} \)文字列を表し\(\)の(私は\)\のビットの第1、及び後ことができる(\)を\プレフィックスに一致します最長の長さ。明らかに、\(Z_ {A、1} = | A | \)恒久的施設。
Zボックスは間隔です。文字列指定された\(\)は、\(\)は、 Zボックスに存在する\([L、R] \ ) 場合は、次の場合にのみ、すべての条件:
- \(\ NE1中のL \) 。
- \(Z_ {L} \ NE0 \) 。
- \(R = L + Z_ {L} -1 \) 。
場合、人気の\(\)の\が(私は\)ビットとエネルギー開始(\)\の接頭辞は少なくとも一致(1 \)\ビット、最長一致文字列がセクション上カバーすることができますこれは、Z-ボックスです。(\ (L \ NE1 \)位置するので\(1 \)は、それ自体に分けて考える接頭辞、非常に特別なものです)
たとえば、\(A = \ {テキストACACTAAC `` ''} \) 、次いで\(Z_ {A}は= [8,0,2,0,0,1,2,0] \)、Z-boxがあります\([3,4]、[6,6]、[7,8] \)。
\(\ BM Z \)を探している配列
与えられた文字列の\(\) 、今私たちが見つける必要がある\(Z_} A {\) 。
ための\(Z_ {1} \) の値は求めていない、位置\(1 \)特別な、接頭辞であるので、我々は別々に処理されました。
我々は今知っていると仮定\(Z_ {2 \ SIM I-1} \) とその\(Zrの\)最大Z-ボックス\([ZL、ジルコニウム] \) 、必要\(Z_ {Aを、I} \)と更新\(ZL、Zrの\)、次いで点\(2 \)の場合:
- \(Zrの<私は\) 。この時点で、我々は、セクションから暴力を導く\(Iは\)後方ビット一致を決定\(Z_ {A、I} \) 。場合\(Z_ {A、I} \ NeOを\)は、次いでせ\(ZL = Iが、Iはジルコニウム= Z_ {A、I} + -1 \) 。
- \(私は\のZr \ GE) 。セット\(I-ZL + 1 = I '\) 、すなわち\(私は' \)スパニングである\(Iは\) Z-ボックスの\([ZL、ジルコニウム] \)に変換され\(A \)の接頭辞の後に\(私は\)の位置。この時点で割った\(2 \)例:
- \(IはZ_ {A、I「} \ルのZr \ +)。明らかに\(\ subsetneq [ZL、ジルコニウム] \ [I、IはZ_ {A、I「} +])を。Zボックスの定義によると、\(\ FORALL J \で[I、IはZ_を+ {A、I「}]、a_j A_ = {J} 1-ZL + \) 。そうから\(A \)の\(Iは\)で始まるビット\(A \)場合マッチプレフィックスとから(I「\)\ビット同様、直接の原因とされている出発\を(Z_ { A = {} Z_ I、I「} \)、\ (ZL、Zrの\)変わりません。
- \(IはZ_ {A、I「}>のZrを\ +)。同様に、\([I、ジルコニウム]、a_j A_ = {J} 1-ZL + \で\ FORALL J \) 。次に\(A \)の\(I \ SIM ZR \)のビット\(A \)ケース一致プレフィックスと\(私は「\ SIM zr- ZL + 1 \) ビットは明らかに、同じである\ (Z_は{I} \ ) が存在し、少なくとも\(Zrが-I + 1 \ ) 。ので、彼から直接\(私は+ Z_ { I「} \) 激しい後方一致を開始ビットが決定され(\を{Z_、I} \) 、およびlet \(ZL = Iは、IがZr = Z_ + {Aを、I} -1 \)(AS \(Z_ {I} \)がしにくい\(0 \ ))。
そのようなシリング\(Z_1 = | | A \)から、上述のように、\(I = 2 \)再帰する(\ | | A私は=)\、決定することができる(z_a \)\アレイ。
求めている以下の\(Z \)コード配列を:
//|a|=n
void z_init(){//求z数组
z[1]=n;//特殊处理z[1]
int zl=0,zr=0;//右端点最大的Z-box
for(int i=2;i<=n;i++)//从i=1递推到i=n
if(zr<i){//第1种情况
z[i]=0;
while(i+z[i]<=s&&a[i+z[i]]==a[1+z[i]])z[i]++;//直接向后暴力匹配
if(z[i])zl=i,zr=i+z[i]-1;//更新右端点最大的Z-box
}
else if(i+z[i-zl+1]<=zr)z[i]=z[i-zl+1];//第2种情况的第1种情况
else{//第2种情况的第1种情况
z[i]=zr-i+1;//z[i]至少有zr-i+1这么多
while(i+z[i]<=s&&a[i+z[i]]==a[1+z[i]])z[i]++;//后面再暴力匹配
zl=i;zr=i+z[i]-1;//更新右端点最大的Z-box
}
}
時間複雑
上述したように求めて\(Zの\)アレイは線形時間複雑である\(\ mathrm {O}(N)\) 。
証明します(感情):場合にのみ、上記の方法を見つけることができ守っ\(I> ZR \)それは、この位置と文字のプレフィックス一致であってもよいが、試合終了後になります(\ ZR)\は、最後の位置の成功と一致するように更新各プレフィックス文字と最も成功したマッチ\(1 \)回、そううまくマッチの総数\(\ mathrm {O}(N)\) ;演算子\(z_i \)、もし次のマッチ暴力(すなわち、最初の遭遇ではない\(2 \)の最初のケース\(1 \)の場合)、最初(1 \)\時間は、それは失敗の総数と一致するが、他にも、マッチが失敗停止する\(\ {O} mathrm(N-)\) 。合計時間は、このように時間が一致費やされる\(\ mathrm {O}( N + N)= \ mathrm O(n)を\) に加え、いくつかの割り当てられた更新\(ZL、\ ZR)といくつかの\(1 \ )回限り\(\ mathrm O(1) \) の操作、まだあなた\(\ mathrm O(n)と \) 。
アプリケーションZアルゴリズム
最も一般的な使用方法は、(このハッシュKMPと線形複雑度を行うことができます)、文字列のパターンマッチングです。パターン列考える\(B \)使用頻度の低い文字テキスト文字列にスペーサを\(A \)前に、および場合でも\(B + C = \ {テキスト`!「A} + \) 。次いで、取得\(z_c \) 、から\(I = | B | +2 \) する(\ \ I = | | C ) 再び掃引、もし\(z_i = | B | \) 、次いで位置合わせ成功。注:いわゆる珍しい文字が文字列に表示されていなければならない、またはバグがあります。使用パターン列場合\(C \)つのテキスト文字列と一致する\(A、B \) 、行うことができる\(D = C + \テキスト { `! '} + A + \テキスト{' @'} + Bを\ )、2枚のセパレータは、同じことができない、またはバグがあろう。
なぜ、Zの文字列パターンが費やした時間と同じハッシュそれにマッチングアルゴリズム?一人一人が、前方一致で開始することができる最長の長さから算出Zアルゴリズムだけプレフィックスかどうかを知る必要が一致する文字列パターン\(C_ {SIM 1 \ | B |} \) 一致、完全に使用しない\ (Z軸\)配列の値。あなただけのビット最長プレフィックス長を一致させるために開始を知りたい場合は、ハッシュは、複雑さの半分はである助けるために必要があるかもしれない\(\ \ログ)、およびZアルゴリズムによる前処理した方が良いです。以下の特定のセクションに参照することが可能で\(2 \)サンプルアイテム。
それだけではなく、一定のZアルゴリズムバイHaxi小さな(順番にハッシュされるべきではないので、カード、FSTはCodeForcesではありません一般的には(Zアルゴリズムはもちろん正しいレートであり、バイHaxi正解率が高い)、二重のハッシュを書く(\ 100 \%の\)それは)。