题目地址
求next[j] ,最大的后缀和前缀相等长度是多少
模板串s: 起点为1, 终点为i
next[j] 代表前半段匹配的子串长度和后半段匹配的子串长度相同且长度最大的 子串。最大的后缀等于前缀。
后缀和前缀
i从下标1开始,j从下标0开始。
因为模式串和模板串匹配的位置是s[i] 和p[j+1],往前错一位
//i 代表模式串s下标,j代表模板串p下标,两个下标要错一位
// KMP匹配过程
for(int i=1,j=0;i<=m;i++){
while(j!=0 &&p[j+1]!=s[i]){ //1.判断j往前倒退,看是否能退, 2.判断判断j能不能往后走
j=ne[j]; //如果j不能往后走,就往前退一步。退一步之后再循环判断能不能往后走
}
// while结束循环有两种条件 1.模板串j下标退无可退了 2.匹配成功
//如果匹配了,j可以往后挪一个位置
if(s[i]==p[j+1]){
j++;
}
if(j==n){
// 说明匹配成功
}
}
kmp就是往前退一步
j=ne[j]
j=ne[ne[j]]
j=ne[ne[ne[j]]
…
//求next过程
for(int i=2,j=0;i<=n;i++){
while(j&& p[i]!=p[j+1]){ //模板串自己和自己对比,找最大前缀
j=ne[j];
}
if(p[i]==p[j+1]){
j++;
}
ne[i]=j;
}
举例:
令j=ne[j] 重新开始匹配,继续做
整体代码:
#include<iostream>
using namespace std;
const int N = 10010, M = 100010;
int n, m;
char p[N], s[M]; // 字符串
int ne[N];
int main() {
// string p,s;
cin >> n >> p + 1 >> m >> s + 1;
//求next过程
for (int i = 2, j = 0; i <= n; i++) {
while (j && p[i] != p[j + 1]) { //模板串自己和自己对比,找最大前缀
j = ne[j];
}
if (p[i] == p[j + 1]) {
j++;
}
ne[i] = j;
}
//i 代表模式串s下标,j代表模板串p下标,两个下标要错一位
// KMP匹配过程
for (int i = 1, j = 0; i <= m; i++) {
while (j && p[j + 1] != s[i]) { //1.判断j往前倒退,看是否能退, 2.判断判断j能不能往后走
j = ne[j]; //如果j不能往后走,就往前退一步。退一步之后再循环判断能不能往后走
}
// while结束循环有两种条件 1.模板串j下标退无可退了 2.匹配成功
//如果匹配了,j可以往后挪一个位置
if (s[i] == p[j + 1]) {
j++;
}
if (j == n) {
// 说明匹配成功
// 题目要求输出匹配成功的起始位置
cout << i - n << endl;
j = ne[j]; //匹配成功后再往后退一步,
}
}
return 0;
}
举例:
j=ne[6]=4;再从这个位匹配。
看不懂,就背下来代码吧~