提示:以下是本篇文章正文内容
一、题目
给定一个字符串 S
,以及一个模式串 P
,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 P
在字符串 S
中多次作为子串出现。
求出模式串 P
在字符串 S
中所有出现的位置的起始下标。
输入格式
第一行输入整数 N
,表示字符串 P
的长度。
第二行输入字符串 P
。
第三行输入整数 M
,表示字符串 S
的长度。
第四行输入字符串 S
。
输出格式
共一行,输出所有出现位置的起始下标(下标从 0
开始计数),整数之间用空格隔开。
数据范围
1≤N≤105
1≤M≤106
输入样例:
3
aba
5
ababa
输出样例:
0 2
二、思路及代码
1.思路
本质是寻找子串自身的最长公共前后缀位置,ne数组就是方便不匹配的时候向后退的步数最少。也就是确保每次匹配过程尽可能不再像常规的暴力的方法从模板串的头开始匹配 ,而是选择一个匹配的中间的部分来进行继续对比,如果不匹配继续后退,但是如果匹配就找到了答案。
next[i] = j 含义是
模板串p[1~j] == p[i - j + 1, i] 匹配上。
2.答案
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1E5 + 10, M = 1E6 + 10;
char s[M], p[N];
int ne[N];
int main()
{
int n, m;
cin >> n >> p + 1 >> m >> s + 1;
//ne 数组处理过程, 只与子串有关, 其实是寻找最长公共前后缀
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;
}
2279

被折叠的 条评论
为什么被折叠?



