KMP
一、算法描述
本篇文章水平不够,讲不清楚KMP到底是怎么回事,以后再更新一下。
本篇文章讲述的是KMP算法, 一个著名的字符串匹配算法,效率很高,\(O(n)\) 的时间复杂度。
难点在于:如何理解 \(next[i]\) ★★★
\(ne[i] = j\) 表示,\(p[1 ~ j] = p[i - j + 1, i]\),从 \(1\) 到 \(j\) 的前缀串,完全等于,从 \(i - j + 1\) 到 \(i\) 的后缀串。
当匹配道某一位置时,下一个位置不匹配,此时为了节约时间,我们要找到一个位置,使得,匹配不成功的点能够继续匹配
暴力做法是往后移动一位,而KMP是直接滑到能够滑到的最远的位置,或者说最少回退多少能够继续匹配。
二、题目描述
给定一个字符串 \(S\),以及一个模式串 \(P\),所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 \(P\) 在字符串 \(S\) 中多次作为子串出现。
求出模式串 \(P\) 在字符串 \(S\) 中所有出现的位置的起始下标。
输入格式
第一行输入整数 \(N\),表示字符串 \(P\) 的长度。
第二行输入字符串 \(P\)。
第三行输入整数 \(M\),表示字符串 \(S\) 的长度。
第四行输入字符串 \(S\)。
输出格式
共一行,输出所有出现位置的起始下标(下标从 \(0\) 开始计数),整数之间用空格隔开。
数据范围
\(1≤N≤10^5\)
\(1≤M≤10^6\)
输入样例:
3
aba
5
ababa
输出样例:
0 2
三、题目来源
四、源代码
#include <iostream>
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
char p[N], s[M];
int ne[N];
int main()
{
cin >> n >> p + 1 >> m >> s + 1;
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 << i - n << ' ';
j = ne[j];
}
}
return 0;
}