KMP——单模式串匹配算法 模板

版权声明: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;
}

当你没成功的时候。不要沮丧,你其实比你想象的人要强,
当你成功的时候,不要张狂,你其实没你想象的那么强。

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/84574130