詳細KMP文字列照合アルゴリズム

はじめに:

コードはどのようなアルゴリズムを学んだが、問題を行うことを学ぶされなかったことを覚えておいてください。

アルゴリズムは本当にティーチ他人に知ることができます。

例を挙げ:T Q Sは、サブ文字列に属している場合、二つの文字列SとTが与えられました。

これは、基本的な文字列照合問題であり、我々は簡単にブルートフォース方法を考えることができます。

ブルートフォース方法:

説明と理解を容易にするために、我々は、パターン文字列のT列、メインの文字列の文字列Sを呼び出します。

文字がある場合に始まるメイン文字列の列挙型のパターン文字列では、同じ試合は後方続け、異なる出発点は、更新し、試合を再起動することです。

ポインタI、Jの定義

I:i番目のメインストリングの一致文字です

J:前者は文字列パターンjの文字がマッチしました

初期状態

sの一致する文字の主な文字列[I] = 'A' とモードの文字列と同じT [J + 1] = 'A'、マッチが成功します。ポインタが移動した後、I ++; J ++。

同様に、そして試合後、

Sメインストリングが次の文字T [I] =「B」及びモードの文字列一致する[Jを+ 1] =「A 」 とは異なるが、一致は失敗します。I = 2更新列挙開始点、マッチングストリングJ == LEN(パターン文字列の長さ)が一致した文字の数までのパターンまで、再開されます。

推定時間計算:O(N * M)

KMPアルゴリズム:

KMPアルゴリズムの性質は、力ずくの方法を最適化されています。削除操作は、再利用可能な情報、無効です。

のは、上記のプロセスのシミュレーションを続けましょう、

いくつかのアップデートがポイントと試合を開始した後、我々はより多くの状態より取得します。手順のブルートフォース方法に従って、一致が失敗した瞬間に、私はこのように、私は5 =に開始点を更新し、列挙から出発し、4 =。

しかし、実際にこのような操作を必要としない、我々は観察しました:

  设K、S [IK] ... S [I-2]、S [I-1] = T [1] ... T [K-1] T [K](S <IK <= I-1

  kが存在しない場合は、出発点として任意の点Dは、(S <D <= I-1)パターン文字列を一致させることはできません。

  kが存在する場合:

    トンであれば[K + 1]!= S [i]は、 それがパターン文字列を一致させることはできません。

    若t[k+1]=s[i],则有可能以i-k为起点匹配出模式串。

①:都会因s[i-1]或之前的某个字符失配而断掉。

②:会因s[i]失配而断掉。

图1:不存在满足条件的k,从任意起点p(s<p<=i-1)都因某字符q匹配不到i-1

图2:存在满足条件的k,但t[k+1]!=s[i],因字符i匹配不到i-1

图3:既存在满足条件的k,t[k+1]=s[i],那么则有可能以i-k为起点匹配出模式串

因而,当匹配失败时,只需找到满足条件的k的最大值。若存在,主串向后匹配,以i-k为起点;若不存在,主串也向后匹配,寻找新的起点。

请思考,选择最大的k是否会漏掉可能的匹配起点?(答案见下文)

算法实现:

我们知道:s[s]..s[i-2]s[i-1]=t[1]..t[j-1]t[j]

  因为s<i-k<=i-1,

  所以s[i-k]..s[i-2]s[i-1]=t[j-k+1]..t[j-1]t[j]

因而我们只需要在模式串已匹配部分寻找k即可。

由于通常情况下模式串长度比较小,我们可以初始化出模式串中每个位置的k值。我们常用next[]数组存储模式串中每个位置的k值。

那么如何求得next[i]?

其实我们求得next[i]的过程等价于用模式串匹配自身的过程。为位置i寻找最长前缀后缀,可以想成用i前面的字符串去匹配模式串,到i最多能够匹配多长。这样以来问题就迎刃而解了,我们只需要进行两次匹配,一次求得next数组,一次匹配模式串。

注意:满足条件的k是指由i-k到i-1能够匹配模式串前k个字符,同时s[i+1]=t[k+1]!

算法流程:

1.初始化指针i=1,j=0

2.循环枚举主串待匹配字符i

3.枚举一个字符就对模式串进行一次匹配:

  若s[i]=t[j+1],则模式串第j+1个字符匹配成功,i++;j++

  若s[i]!=t[j+1],匹配失败,则更新j等于最长的满足条件的k,i++

4.当j=len时,匹配成功,跳出循环。

代码如下:

 1 void get_next()
 2 {
 3     int i,j;
 4     j=0;
 5     next[1]=0;
 6     for(i=2;i<=lent;i++){
 7         while(j>0&&t[j+1]!=t[i])j=next[j];
 8         if(t[j+1]==t[i])j++;
 9         next[i]=j;
10     }
11 }
12 
13 void KMP()
14 {
15     int i,j;
16      j=0;
17      for(i=1;i<=lens;i++){
18          while(j>0&&t[j+1]!=s[i])j=next[j];
19          if(t[j+1]==s[i])j++;
20          if(j==lent)ans[++cnt]=i-j+1;
21     }
22 }

 

next数组的求得很关键,这几天要期末考试,学业繁重。日后加图完善!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

おすすめ

転載: www.cnblogs.com/Neat-Foxes/p/12098930.html