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 }
复制代码

 

 

posted @   Conqueror712  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示