831. KMP字符串
题目链接
831. KMP字符串
给定一个模式串 \(S\),以及一个模板串 \(P\),所有字符串中只包含大小写英文字母以及阿拉伯数字。
模板串 \(P\) 在模式串 \(S\) 中多次作为子串出现。
求出模板串 \(P\) 在模式串 $S4 中所有出现的位置的起始下标。
输入格式
第一行输入整数 \(N\),表示字符串 \(P\) 的长度。
第二行输入字符串 \(P\)。
第三行输入整数 \(M\),表示字符串 \(S\) 的长度。
第四行输入字符串 \(S\)。
输出格式
共一行,输出所有出现位置的起始下标(下标从 \(0\) 开始计数),整数之间用空格隔开。
数据范围
\(1≤N≤10^5\)
\(1≤M≤10^6\)
输入样例:
3
aba
5
ababa
输出样例:
0 2
解题思路
KMP
考虑一般的暴力匹配过程,即母串与匹配串一个一个字符匹配,当两个字符不相等时,再移动母串,匹配串从零开始与母串匹配,其实匹配串没必要从零开始,可以考虑之前 \(1\sim j\) 是匹配成功的,先求出这样的 \(next[j]\) 数组,即 匹配串中 \(1\sim j\) 的最长非平凡公共前后缀长度,这样匹配串移动的时候只需要移动到 \(next[j]\) 的位置上,因为 \(1\sim j\) 这部分与匹配串是匹配的,所以关键在于求 \(next[j]\) 数组
- 时间复杂度:\(O(n+m)\)
代码
// Problem: KMP字符串
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/833/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int n,m,ne[100005];
string p,s;
int main()
{
cin>>n>>p;
cin>>m>>s;
p=' '+p,s=' '+s;
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;
}
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)
{
cout<