原理浅析
zyf:
求失配的过程和最后比较的过程差不多,因为每次都是如果不匹配就跳到它失配的位置。
至于为什么是这样,可以想象一下失配也就是说头和尾上的一段字符串是一模一样的,那么我们在头上不停地往前跳,也就相当于在结尾不停地往后跳(自己体会一下)。
KMP一开始看有点晕,你先要知道的是,它是先自己和自己弄,再和大串弄
i是a串(大串)的指针,j是b串(小串)的指针
E.G.
a b a b a b a b e
a b a b e
啊,你发现这里炸了,因为b[1]=b[3],b[2]=b[4]你完全可以,直接这样:
a b a b a b a b e
。。。。 a b a b e
而不是这样:
a b a b a b a b e
. a b a b e
代码
原理就是这样,代码实现上
预处理出这样一个数组p[j],表示当匹配到b数组的第j个字母而第j+1个字母不能匹配了时,新的j最大是多少。
这样可以使得A[i-j+1..i]与B[1..j]保持匹配(此处为新的j)。
然后,下一位如果还是不能匹配,再把前一个j翻出来,再匹配一次,直到找不到相同的前缀了也就是j=0了,就只能把整个串往后挪一位了
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000001;
char a[maxn],b[maxn];
int la,lb,p[maxn];
int main()
{
scanf("%s%s",a+1,b+1);
la=strlen(a+1); lb=strlen(b+1);
int j=0;//首先b和b自身匹配
p[1]=0;
for (int i=2; i<=lb; i++)//从2开始?
{
while (j>0 && b[i]!=b[j+1]) j=p[j];
if (b[i]==b[j+1]) j++;
p[i]=j;//更新p
}
j=0;
for (int i=1; i<=la; i++)
{
while (j>0 && a[i]!=b[j+1]) j=p[j];
if (a[i]==b[j+1]) j++;
if (j==lb)
{
printf("%d\n",i-lb+1);//输出子串的位置
j=p[j];
}
}
for (int i=1; i<=lb; i++) printf("%d ",p[i]);
return 0;
}