KMPアルゴリズムについて
人々はクヌース呼び出すようKMPアルゴリズムは、DEKnuth、JHMorrisとVRPrattによって提案され、改善された文字列照合アルゴリズムである - モリス - プラット動作(KMPアルゴリズムをいいます)。情報を用いてコアKMPアルゴリズムは高速マッチングの目的を達成するために、メインの文字列パターン文字列の一致の数を最小限にするために、一致しません。特定の実装()は、ローカルマッチング機能自体は、情報パターン文字列が含まれる次の機能によって実現されます。アルゴリズムO(M + N)のKMP時間複雑。
簡単に言えば:
KMPアルゴリズムは、同じパターン文字列を使用して移動する接頭辞と接尾辞最長で、かつ高速なマッチングを実現するように、メインの文字列のバックを必要としません。
例えば:
以下は、不一致が矢印のパターン文字列の部分文字列がABである前に、同じ最長の接頭辞と接尾辞を見つけるために、矢印で発生したとき、
およびAB ABは位置を移動サフィックスに接頭辞、
同じトークンを一致させるために継続し、発生しません。矢印は最長で同じ接頭辞と接尾辞をサブストリングの前に見つかったパターン文字列を一致させる、
そしてそれがメインの文字列の一致が失敗したの長さを超えているので、位置aに移動する接頭辞は、接尾辞。
別の例:
以下は、ミスマッチがABAのサブ矢印パターン文字列の前に同じの最長の接頭辞と接尾辞を見つけるために、矢印で発生したとき、
および接尾辞ABAのABAのプレフィックスが位置を移動し、
同じトークンを一致させるために継続し、それは発生しません。矢印は最長で同じ接頭辞と接尾辞をサブストリングの前に見つかったパターン文字列を一致させる、
と接尾辞aの位置aに移動プレフィックスが、一致し続け、マッチが成功します。
得られ次のアレイ
= 1、及びそれに対応する次の配列は、1(p.sizeである)[0]、次の - - 文字列セットモード)パターン文字列は、インデックス(0からp.sizeであることに留意すべきであり、pは1です。
void getNext(string p, int *next)
{
next[0]=-1;
int i=0,j=-1;//j是前缀,y是后缀
while (i<p.size())
{
if(j==-1||p[i]==p[j])
{
++i;
++j;
next[i]=j;
}
else
{
j=next[j];//回溯
}
}
}
理解することが最も難しいフレーズです、
j=next[j];//回溯
なぜこのようにですか?しかし待ち時間は、例えば:
!私は5 =、J = 3、黒矢印の位置、すなわち、P [I] = P [ j]は、I P.SIZE(0から、およびJインデックス)、次いで、J =次の[J]、すなわち、J = 1は、赤矢印不等の即ち位置はそれほど時間背中を保存、バックJ = 0まで継続します。元の日付バックプレフィックスは、当社は、配列に格納された次の各インデックスの接頭辞と接尾辞最長に等しく、知られています。
C ++の実装:
#include<iostream>
using namespace std;
void getNext(string p, int *next)
{
next[0]=-1;
int i=0,j=-1;
while (i<p.size())
{
if(j==-1||p[i]==p[j])
{
++i;
++j;
next[i]=j;
}
else
{
j=next[j];
}
}
for(int i=0;i<=p.size();i++)
{
cout<<next[i]<<" ";
}
}
int kmp(string x,string y,int *next)
{
int i=0,j=0;
while(true)
{
if(x[i]==y[j]||j==-1)
{
i++;j++;
}
else
{
j=next[j];
}
if(i==x.size()||j==y.size()) break;
}
if(j==y.size())
{
return i-j;
}
else return -1;
}
int main()
{
string x;string y;
int *next=new int[1000005];
cin>>x>>y;
getNext(y,next);
int ans=kmp(x,y,next);
cout<<ans;
return 0;
}