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
3 aaa 12 aabaabaabaab 0
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數組,就得靠本身不斷的磨練了。