1. 程式人生 > >KMP——單模式串匹配演算法 模板

KMP——單模式串匹配演算法 模板

直接上程式碼,註釋很清晰

#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;
}

當你沒成功的時候。不要沮喪,你其實比你想象的人要強,
當你成功的時候,不要張狂,你其實沒你想象的那麼強。