KMP模板
首先推荐一下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[i-1]+1; 9 j++; i++; 10 } else { 11 if(j != 0) // 不相等,判断是否为0 12 { 13 j = next[j-1]; // 移动 14 } else next[i++] = 0; 15 } 16 } 17 }
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[i-1]+1; 16 j++; i++; 17 } else { 18 if(j != 0) // 不相等,判断是否为0 19 { 20 j = next[j-1]; // 移动 21 } else next[i++] = 0; 22 } 23 } 24 } 25 int kmp() 26 { 27 int i,j; 28 for(i=0,j=0; i < n1 && j < n2; ) 29 { 30 if(j == n2) break; // 匹配结束,跳出循环 31 if(str[i] == pattern[j]) // 匹配成功,同时后移 32 { 33 i++; 34 j++; 35 } else { 36 if(j != 0) j = next[j-1]; // 匹配失败,若j不为0,移动 37 else i++; // j为零,i移动 38 } 39 } 40 if(j == n2) return i-j; // 返回主串中的下标 41 else return -1; // 匹配失败,返回异常 42 } 43 int main() 44 { 45 cin >> str >> pattern; 46 n1 = strlen(str); 47 n2 = strlen(pattern); 48 getnext(); 49 cout << kmp(); 50 return 0; 51 }

浙公网安备 33010602011771号