KMP算法講解

KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發現,所以人們稱它爲克努特——莫里斯——普拉特操做(簡稱KMP算法)。KMP算法的關鍵是利用匹配失敗後的信息,儘可能減小模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現一個next()函數,函數自己包含了模式串的局部匹配信息。時間複雜度O(m+n)。ios

以上是百度百科對KMP算法的介紹,如何把實現把樸素算法變成O(m+n)的時間複雜度呢,從上面介紹能夠看出來,KMP算法利用了一個next數組,因此須要預處理,下面咱們就來說解KMP算法。c++

由於懶得畫圖還怕畫很差,因此我錄製成了視頻的格式。算法

Bilibili視頻:https://www.bilibili.com/video/av40137935數組

這是一道KMP裸題,請自行嘗試AC:傳送門ide

看完上面,你大體就應該清楚如何利用KMP進行線性匹配了,可是KMP算法的精髓其實不是進行簡單的串匹配,精髓應該在於next數組的應用,以及擴展的next_val數組的運用,能夠快速的尋找循環節,前綴匹配等等一些複雜的字符串問題。函數

下面將以一道例題說明next數組的強大spa

HDU 1358(Period).net

Problem Description
For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K , that is A concatenated K times, for some string A. Of course, we also want to know the period K.
Input
The input file consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) - the size of the string S. The second line contains the string S. The input file ends with a line, having the number zero on it.
Output
For each test case, output 「Test case #」 and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.
SampleInput
3
aaa
12
aabaabaabaab
0
 
SampleOutput
Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

題意:給一個長爲n的字符串,問字符串的前綴是否是週期串,若是是週期串,輸出前綴的最後一個字母的位置和最短週期code

應該如何思考呢,已經說明了這是一道KMP的題,用KMP進行串匹配嗎?顯然不是,那麼確定就是利用next數組的性質了,對於前i個字符,若是next[i]不等於零,那麼說明在此字符串的前綴中,有一部分[0,next[i]]和本字符串[i-next[i],i]的這一部分是相同的。若是這i個字符組成一個週期串,那麼錯開的一部分[next[i],i]剛好是一個循環節。(換句話說,若是知足next[i]不等於零 && [next[i],i]是循環節這兩點,就能夠說明前i個字符組成一個週期串),那麼咱們只須要跑一遍next數組便可,代碼:視頻

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n;
 5 string str;
 6 int nxt[1000005];
 7 
 8 void getnext(){
 9     int i = 0, j = -1, len = str.size();
10     nxt[0] = -1;
11     while(i < len){
12         if(j == -1 || str[i] == str[j])
13             nxt[++i] = ++j;
14         else
15             j = nxt[j];
16     }
17 }
18 
19 int main(){
20     ios_base::sync_with_stdio(false),cout.tie(0),cin.tie(0);
21     int tot = 1;
22     while(cin>>n && n){
23         cin>>str;
24         getnext();
25         cout << "Test case #" << tot++ << endl;
26         for(int i = 2; i <= n; i++){
27             if(nxt[i] != 0 && i % (i - nxt[i]) == 0)
28                 cout << i << " " << i/(i - nxt[i]) << endl;
29         }
30         cout << endl;
31     }
32 
33     return 0;
34 }

 

關於KMP算法就講到這裏了,這是一個很簡單的串匹配算法,但可否掌握其思想以及運用其next數組,就得靠本身不斷的磨練了。

相關文章
相關標籤/搜索