KMP算法简析
暂且就先以一道洛谷板子题作为讲解吧,
直接上代码,部分代码参考了优秀的大佬们的优秀的题解。(确实人家的码风很好呜呜呜)
1 #include<bits/stdc++.h> 2 #define ios ios::sync_with_stdio(false);cin.tie(0),cout.tie(0) 3 typedef long long ll; 4 //const ll mod = 1e9+7; 5 //const ll mod = 1000003; 6 #define endl "\n" 7 using namespace std; 8 9 const ll LEN = 1000001; 10 int KMP[LEN]; //用于记录 当匹配到模式串的第i位之后失配 跳转到模式串的位置的数组 也可以理解为当前位置j前面的最长前后缀的长度 11 int len_s; //str主串的长度 12 int len_p; //pattern_str模式串的长度 13 int j; //用于模式串的指针,可以看作表示当前已经匹配完的模式串的最后一位的位置 14 //说人话就是 j表示模式串匹配到哪里了 15 char s[LEN],p[LEN]; //主串和模式串的声明 感觉string也可以 但是如果想从下标为1开始操作就不太方便了 而且string目测会慢一些 16 int main(){ 17 cin >> s + 1; //这里+1的原因是让操作的下标从1开始 18 cin >> p + 1; 19 len_s = strlen(s + 1); 20 len_p = strlen(p + 1); 21 j = 0; 22 for (int i = 2; i <= len_p; i++){ //让模式串自己匹配自己获取KMP数组 23 while ( j && p[i] != p[j + 1]){ 24 j = KMP[j]; 25 } 26 if(p[j + 1] == p[i]){ 27 j++; 28 } 29 KMP[i] = j; 30 } 31 j = 0; 32 for(int i = 1; i <= len_s; i++){ //与主串相比,从而输出匹配位置 33 while(j > 0 && p[j+1] != s[i]){ 34 j = KMP[j]; 35 } 36 if (p[j + 1] == s[i]) { 37 j++; 38 } 39 if (j == len_p) { 40 cout << i - len_p + 1 << endl; 41 j = KMP[j]; 42 } 43 } 44 for (int i = 1; i <= len_p; i++){ 45 cout << KMP[i] << " "; 46 } 47 return 0; 48 }
这里特别说明一下,将j指针回溯,其实等价于将模式串按照匹配的最长前后缀移动,这两个的效果是一样的。
实在不理解就画个图理解一下就理解了(什么奇怪的句子)。
图解:
初态:
第一次不匹配:
目前状态的最长前后缀:j = 2
接下来开始回溯,注意,左边是回溯,右边是移动模式串,两种方式等价:
现在,j移动到了2的位置。
于是我们就可以循环这个操作,直到得出结果。
扩展烤馍片:
1 void exkmp(){ 2 int l = 1, r = 0; 3 z[1] = 0; 4 for (int i = 2;i <= n;i++){ 5 if (i > r){ 6 z[i] = 0; 7 } 8 else{ 9 int k = i - l + 1; 10 z[i] = min(z[k], r - i + 1); 11 } 12 while(i + z[i] <= n && s[z[i] + 1] == s[i + z[i]]){ 13 ++z[i]; 14 } 15 if (i + z[i] - 1 > r){ 16 l = i; 17 r = i + z[i] - 1; 18 } 19 } 20 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人