笔记:
给定模板串P和模式串S。
要求在S中查找P。
问题关键在于处理“失配”。
我们引入一个数组nxt,表示:
若nxti=j,那么P[1,j]=P[i−j+1,i],nxti=maxj。
也就是“P中以i结尾的非前缀字串”与“P的前缀”所能匹配的最长长度。
而我们在暴力算法中,肯定是每次把P整个往后移动一位,再进行比较。
然而我们对P自匹配出nxt的时候,就是查找P的“自相似性”,也就是自己中的循环节。
我们来看一张示意图。
在上图中,P要移动了,但是我们发现没有必要把P往后移动一格,而应该直接跳到nxt的位置上,因为这样确保前一段是相同的,如果一位一位跳太“节省时间”了,数据范围稍大就会TLE。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100010, M = 1000010;
char p[N], s[M];
int n, m, nxt[N], f[N];
int main() {
cin >> n >> p + 1 >> m >> s + 1;
//求nxt的过程
for (int i = 2, j = 0; i <= n; i++) {
while (j && p[i] != p[j + 1]) j = nxt[j];
if (p[i] == p[j + 1]) j++;
nxt[i] = j;
}
//kmp匹配过程
for (int i = 1, j = 0; i <= m; i++) {
while (j && s[i] != p[j + 1]) j = nxt[j];
if (s[i] == p[j + 1]) j++;
if (j == n) {
//匹配成功了
printf("%d ", i - n);
j = nxt[j];
}
}
return 0;
}