版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/84574130
直接上代码,注释很清晰
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000010;
int kmp[MAXN];
int la,lb,j;
char a[MAXN],b[MAXN];
int main()
{
cin>>(a+1);
cin>>(b+1);
la=strlen(a+1);
lb=strlen(b+1);
j=0;
for (int i=2;i<=lb;i++)
{
while(j&&b[i]!=b[j+1])
//此处判断j是否为0的原因在于,如果回跳到第一个字符就不用再回跳了
j=kmp[j];
//通过自己匹配自己来得出每一个点的kmp值
if(b[j+1]==b[i])j++;
kmp[i]=j;
//i+1失配后应该如何跳
}
j=0;//j可以看做表示当前已经匹配完的模式串的最后一位的位置
//如果看不懂,你也可以理解为j表示模式串匹配到第几位了
for(int i=1;i<=la;i++)
{
while(j&&b[j+1]!=a[i]) j=kmp[j];
//如果失配,那么就不断向回跳,直到可以继续匹配
if (b[j+1]==a[i]) j++;
//如果匹配成功,那么对应的模式串位置++
if (j==lb)
{
cout<<i-lb+1<<endl;
j=kmp[j];
//继续匹配
}
}
for (int i=1;i<=lb;i++)
cout<<kmp[i]<<" ";
return 0;
}
例题
据说是boi2009。。。
描述 Description
给你一个字符串,它是由某个字符串不断自我连接形成的。但是这个字符串是不确定的,现在只想知道它的最短长度是多少.
输入格式 Input Format
第一行给出字符串的长度,1 < L ≤ 1,000,000. 第二行给出一个字符串,全由小写字母组成.
输出格式 Output Format
输出最短的长度
样例输入 Sample Input
8
cabcabca
样例输出 Sample Output
3
时间限制 Time Limitation
1s
题解
根据kmp(即next)数组的性质,有i%(i-next[i])==0&&next[i]!=0
则说明字符串前i位循环,而且循环节长度为:i-next[i],循环次数为:i/( i-next[i])
因为不要求整除,所以ans=la-next[la](这是真学到了知识,也说明,KMP算法可能会根据next数组的特殊性质出题,得小心啊!)
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000010;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
return num*f;
}
int kmp[MAXN];
char a[MAXN];
int main()
{
int la=read();
cin>>(a+1);
int j=0;
for (int i=2;i<=la;i++)
{
while(j&&a[i]!=a[j+1])
//此处判断j是否为0的原因在于,如果回跳到第一个字符就不用再回跳了
j=kmp[j];
//通过自己匹配自己来得出每一个点的kmp值
if(a[j+1]==a[i])j++;
kmp[i]=j;//i+1失配后应该如何跳
}
printf("%d\n",la-kmp[la]);
//根据kmp(即next)数组的性质,有i%(i-next[i])==0&&next[i]!=0
//则说明字符串前i位循环,而且循环节长度为:i-next[i],循环次数为:i/( i-next[i])
//因为不要求整除,所以ans=la-next[la]
return 0;
}
当你没成功的时候。不要沮丧,你其实比你想象的人要强,
当你成功的时候,不要张狂,你其实没你想象的那么强。