1. 程式人生 > 實用技巧 >KMP模板

KMP模板

首先推薦一下B站上一個阿三哥講的KMP,通俗易懂,深入淺出就是英語口語有些彆扭

傳送門:汪都能聽懂的KMP字串匹配演算法【雙語字幕】

(時間有限,有機會把配圖補上)

匹配原理:

kmp演算法是一種模式匹配演算法,時間複雜度為O(m+n)。

kmp最大的特點是,當在某個字元匹配不成功時,不需要從頭開始,利用模式串的字首和字尾來進行優化,若存在相同的字首和字尾,則只需要在相同的字首之後繼續匹配即可。難點在於相同的字首和字尾如何得到,即next陣列如何得到。

next陣列:

兩個下標指標i,j,初始j=0,i=1,比較a[i]和a[j],如果相同,兩個下標同時向後移,如果不相同,則j = next[j-1],繼續比較。時間複雜度O(n),空間複雜度O(n)。

利用next陣列匹配:

進行模式匹配時,如果匹配失敗,則模式串下標移動到next[i-1]的值的位置,繼續匹配。時間複雜度O(m)。

直接上模板:

next陣列計算:

 1 void getnext()
 2 {
 3     next[0] = 0; // 第一個元素初始化為0
 4     int i,j;
 5     for(i=1,j=0; i < n2; )
 6     {
 7         if(pattern[i] == pattern[j]) { // 如果相等,計算next陣列,然後同時後移
 8             next[i++] = next[j++]+1;
9 } else { 10 if(j != 0) // 不相等,判斷是否為0 11 { 12 j = next[j-1]; // 移動 13 } else next[i++] = 0; 14 } 15 } 16 }

kmp演算法實現:

 1 int kmp()
 2 {
 3     int i,j;
 4     for(i=0,j=0; i < n1 && j < n2; )
 5     {
 6         if(j == n2) break
; // 匹配結束,跳出迴圈 7 if(str[i] == pattern[j]) // 匹配成功,同時後移 8 { 9 i++; 10 j++; 11 } else { 12 if(j != 0) j = next[j-1]; // 匹配失敗,若j不為0,移動 13 else i++; // j為零,i移動 14 } 15 } 16 if(j == n2) return i-j; // 返回主串中的下標 17 else return -1; // 匹配失敗,返回異常 18 }

完整測試程式碼:

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 char str[100];
 5 char pattern[100];
 6 int next[100];
 7 int n1,n2;
 8 void getnext()
 9 {
10     next[0] = 0; // 第一個元素初始化為0
11     int i,j;
12     for(i=1,j=0; i < n2; )
13     {
14         if(pattern[i] == pattern[j]) { // 如果相等,計算next陣列,然後同時後移
15             next[i++] = next[j++]+1;
16         } else {
17             if(j != 0) // 不相等,判斷是否為0
18             {
19                 j = next[j-1]; // 移動
20             } else next[i++] = 0;
21         }
22     }
23 }
24 int kmp()
25 {
26     int i,j;
27     for(i=0,j=0; i < n1 && j < n2; )
28     {
29         if(j == n2) break;  // 匹配結束,跳出迴圈
30         if(str[i] == pattern[j]) // 匹配成功,同時後移
31         {
32             i++;
33             j++;
34         } else {
35             if(j != 0) j = next[j-1]; // 匹配失敗,若j不為0,移動
36             else i++; // j為零,i移動
37         }
38     }
39     if(j == n2) return i-j; // 返回主串中的下標
40     else return -1; // 匹配失敗,返回異常
41 }
42 int main()
43 {
44     cin >> str >> pattern;
45     n1 = strlen(str);
46     n2 = strlen(pattern);
47     getnext();
48     cout << kmp();
49     return 0;
50 }
View Code