KMP模板
阿新 • • 發佈:2020-08-05
首先推薦一下B站上一個阿三哥講的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