KMP是极其经典与有趣的算法,
代码如下
#include<cstdio>
#include<cstring>
using namespace std;
char a[1000010],b[1000010];
int main()
{
scanf("%s",a);
scanf("%s",b);
int n=strlen(a),m=strlen(b);
int max_len[m]={0};//max_len[i]=j,表示b[i]前的字符串包括b[i]的最长公共前后缀的长度
int i,j=1,k=-1;//k表示max_len数组的左指针,j为右指针
//左指针表示前缀的最后一个元素,
//j表示已确定后缀最后一个元素后面待定的元素
max_len[0]=0;//b[0]前包括b[0]的字符串的最长公共前后缀为零 ,必然
//......下面开始造max-len数组,注意,是针对b一个字符串的
while(j<m)
{
if(b[k+1]==b[j])//k+1与i都是以确定
{
max_len[j]=++k+1;
//k表示以确定的前缀的最后一个元素的坐标,后面的配对了,自然要++k,
//数组是零开头的,再+1,表示长度
j++;
}
else if(k+1==0&&b[k+1]!=b[j]){//不配对 ,往后退,直到k=-1,
max_len[j]=0;
j++;
}
else{
k=max_len[k]-1;//数组是长度,-1是下标,数组元素下标为k以前包括k的公共前后缀,给k
}
}
//以上, max_len数组就完成了,上面的配对都是针对于b字符串的,注意下面的都是两个字符串之间的
j=0;i=0;
k=0;
while(j<n&&i<m)
{
k++;
// printf("j=%d i=%d max_len[i]=%d\n",j,i,max_len[i]);
if(a[j]==b[i])//j是a串的下标,i是b串的下标,元素相等,i,j同时加
{
// printf("(1)\n");
if(i==m-1)//i走到头了,其实就已经刻意在a上找到一段b串了,这里没有break,是为了看看有几段b
{
printf("%d\n",j-i+1);//在a的什么位置开始,有b,打印
i=max_len[i]-1;
}
i++;j++;
}
else if(i!=0){//不配对,i!=0,就往后推
i=max_len[i-1];
// printf("(2)\n");
}
else {//if(max_len[i]==0),,在初位置不配对,只j++,往后再判断
i=0;j++;
// printf("(3)\n");
}
}
for(i=0;i<m;i++) printf("%d ",max_len[i]);
return 0;
}