Files
python/TangDou/AcWing/KMP/831_FullZhuShi.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

59 lines
3.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int N = 100010; //模板串最大长度限制
const int M = 1000010; //模式串最大长度限制
int n; //模板串长度
int m; //模式串长度
int ne[N]; //next数组
char s[M]; //模式串
char p[N]; //模板串
/**
KMP的思想
1、先考虑一下暴力怎么做?
2、因为暴力作法,在对比多次后失败后,需要回到头才能跟目标串的下一个字符开始匹配,效率太差,需要优化。
3、优化的思路受暴力作法的启发,试图在匹配过程中找到一些可以重复利用的特征,加快匹配的速度,即不想完全从头再次对比了,能少退就少退。
4、经画图可以发现,如果我们能整理出一套模板串前缀与后缀的公共子中的最大长度,发生不匹配的时候,不用跳到头,按最大前后匹配子串长度
跳最省时间。如果这时再发生对比不匹配问题,就再次尝试较小一点的前后缀相同字符,依此类推,直到退无可退,那就从头开始对比。
KMP匹配过程:对于模板串我们先提前预处里出ne数组,然后在匹配的时候,如果当前位置的模式串和模板串匹配,那么指针向后移动,
如果当前位置的模式串和模板串不匹配,我们就要将模板串的指针移动到 ne[j] 的位置继续匹配,
当j移动到模板串最后的位置(等于模板串的长度),就说明匹配成功,模板串是模式串的字串。
最长相等前后缀-(最长公共前后缀)
*/
int main() {
cin >> n >> (p + 1) >> m >> (s + 1);
//一、求ne数组
//i:当前试图进行匹配的S串字符,j+1是模板串当前试图与S串i位置进行匹配的字符
//j:退无可退,无需再退
//i:是从2开始的,因为ne[1]=0,表示第1个不匹配,只能重头开始,不用算
for (int i = 2, j = 0; i <= n; i++) {
while (j && p[i] != p[j + 1]) j = ne[j];
//如果是匹配情况发生了,那么j移动到下一个位置
if (p[i] == p[j + 1]) j++;
//记录j到ne数组中
ne[i] = j;
}
/**
KMP算法对蛮力算法的修改就两点,第一点是失配时i不动,j不再回到模式串开头而是回到ne[j],
另外当j = ne[j] = 0表示模式串退到了通配符哨兵,此时文本串指针i应该右移一位,
j也应该从头比对,同样是i++,j++,与匹配时的动作一致。
*/
//二、匹配字符串
//i:当前试图进行对比的S串位置
//j:最后一个已完成匹配的P串位置,那么,当前试图与S串当前位置i进行尝试对比匹配的位置是j+1
for (int i = 1, j = 0; i <= m; i++) {
while (j && s[i] != p[j + 1]) j = ne[j];//不行就退吧,当j==0时,表示退无可退,无需再退
//如果是匹配情况发生了,那么j移动到下一个位置
if (s[i] == p[j + 1]) j++; //匹配则指针前行,i不用++,因为它在自己的for循环中,自带++
if (j == n) { //如果匹配到最大长度,说明完成了所有位置匹配
printf("%d ", i - n); //输出开始匹配位置
j = ne[j]; //回退,尝试继续进行匹配,看看还有没有其它可以匹配的位置
}
}
return 0;
}