嗯。。。我不会讲什么原理之类的 我只会讲一下自己搞了很久才明白的地方
1.关于j的通俗定义
j是一个指针 相当于当前i对应的s1在s2里面的位置 若根本就没有一个相同的字符那就是0
2.关于next数组的通俗理解
对于s2的一个字母s next[s]相当于s所在的字符串(这个字符串从s向后延伸 长度不定 且这个字符串等于整个字符串的前缀)在整个字符串从前往后的第一个位置
3.关于每次j怎么变化
若j的下一个指向的这个字母与i的不相同 那相当于要把整个s2字符串往右移 相当于就是把j移到next[j]的位置(这看似往前移了 实质上把j往左移是把整个s2往后移)
4.j的边界
当j等于0 说明之前的j指向的那个字母是无法找到一个串与这个串紧接着的前面的那一坨里的一个前缀相等 所以我们只有把i往右移
#include<bits/stdc++.h>
using namespace std;
char s1[1000005],s2[1000005];
int next[1000005];
int len1,len2;
inline void getnext()
{
int j=0;
for(int i=2;i<=len2;i++)
{
while(j&&s2[i]!=s2[j+1]) j=next[j]; //此处判断j是否为0的原因在于,如果回跳到第一个字符就不用再回跳了
if(s2[j+1]==s2[i]) j++;
next[i]=j;
}
}
int kmp()
{
int i=0,j=0,f=0;
for(int i=1;i<=len1;i++)
{
while(j>0&&s2[j+1]!=s1[i])
{
j=next[j];
}
if(s2[j+1]==s1[i]) j++;
if(j==len2)
{
f=1;
cout<<i-len2+1<<endl;
// j=next[j];
}
}
return f;
}
int main()
{
scanf("%s",s1+1);
scanf("%s",s2+1);
len1=strlen(s1+1);
len2=strlen(s2+1);
getnext();
if(kmp()!=1) cout<<"NO"<<endl;
/*for(int i=1;i<=len2;i++)
{
cout<<next[i]<<" ";
}*/
return 0;
}