kmp AcWing 831. KMP字符串
给定一个字符串 𝑆,以及一个模式串 𝑃,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 𝑃 在字符串 𝑆 中多次作为子串出现。
求出模式串 𝑃 在字符串 𝑆 中所有出现的位置的起始下标。
输入格式
第一行输入整数 𝑁,表示字符串 𝑃 的长度。
第二行输入字符串 𝑃。
第三行输入整数 𝑀,表示字符串 𝑆 的长度。
第四行输入字符串 𝑆。
输出格式
共一行,输出所有出现位置的起始下标(下标从 0 开始计数),整数之间用空格隔开。
#include<iostream>
using namespace std;
const int N=10010,M=100010;
int n,m;
char p[N],s[M];
int ne[N];
int main()
{
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;
}
// kmp匹配过程
for (int i=1,j=0;i<=m;i++)
{
while (j && s[i]!=p[j+1]) j=ne[j];
if (s[i]==p[j+1]) j++;
if (j==n)
{
printf ("%d ",i-n);
j=ne[j];
}
}
return 0;
}
求next
数组过程(next
函数构建部分):
这是一段关键的代码,用于构建模式字符串p
的next
数组
初始化:通过for
循环,从i = 2
开始(因为next[1]
通常默认设为0
,这里从第二个字符位置开始计算后续的next
值),同时设置j = 0
,这里j
可以看作是一个辅助指针,用于追溯已经匹配过的部分。
回溯与匹配判断:在循环中,while (j && p[i]!=p[j+1]) j=ne[j];
这行代码的作用是,当当前字符p[i]
与p[j + 1]
不匹配时(j
不为0
表示之前已经有部分匹配了,需要根据next
数组回溯到合适的位置继续比较),就通过j = ne[j]
不断回溯j
的值,直到找到可以继续匹配的位置或者j