KMP算法講解


KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發現,因此人們稱它為克努特——莫里斯——普拉特操作(簡稱KMP算法)。KMP算法的關鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現一個next()函數,函數本身包含了模式串的局部匹配信息。時間復雜度O(m+n)。

以上是百度百科對KMP算法的介紹,如何把實現把朴素算法變成O(m+n)的時間復雜度呢,從上面介紹可以看出來,KMP算法利用了一個next數組,所以需要預處理,下面我們就來講解KMP算法。

因為懶得畫圖還怕畫不好,所以我錄制成了視頻的格式。

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

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

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

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

HDU 1358(Period)

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的字符串,問字符串的前綴是不是周期串,如果是周期串,輸出前綴的最后一個字母的位置和最短周期

應該如何思考呢,已經說明了這是一道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數組,就得靠自己不斷的磨練了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM