KMP算法的核心是利用匹配失敗後的信息,儘可能減小模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是經過一個getnext()函數實現,函數自己包含了模式串的局部匹配信息。KMP算法的時間複雜度O(m+n)。其中最難理解的部分即next數組的求法以及回溯c++
**前綴數組中存儲的是這個字符串前綴和後綴中相同子串的最長長度 **web
next 數組考慮的是除當前字符外的最長相同前綴後綴算法
以 agctagcagctagctg 爲例數組
** start**svg
將next數組初始化以後爲:函數
–>將模串依次向後移比較至此測試
–>回溯code
此時對比,小串長爲3,j=3;回溯,j=next[j=3]=0;此時i=7;繼續匹配依次後移xml
–>再回溯blog
此時對比,小串長爲3,j=7;回溯,j=next[j]=3,i=14;繼續匹配,當pat[i=14]=pat[j=3],i++,j++,即next[15]=4;
–>j=next[j=4]=0;–>j=next[j=0]=-1;–>i++=,j++,next[i=16]=j=0;
** end**
//獲取前綴數組 void GetNext(char *pat){ int i=0,j=-1; next[0]=-1; while(i<n){ //n爲模板串pat的長度 if(j==-1||pat[i]==pat[j]){ i++,j++; next[i]=j; } else j=next[j]; } } //第二種next數組 // abcab // 00012 void calc_next() { next[0] = 0; //下標從1開始 next[1]=0; for (int i = 1, j = 0; i < n; i++) { //i=2;i<=n while (j > 0 && pat[i] != pat[j])//pat[i]!=pat[j+1] j = next[j - 1]; //j=next[j] if (pat[i] == pat[j]) //pat[i]==pat[j+1] j++; next[i] = j; } }
獻上一道前綴數組尋找循環節的問題
題號:hdu-1358
題意:一個字符串的前綴是從第一個字符開始的連續若干個字符,例如」abaab」共有5個前綴,分別是a, ab, aba, abaa, abaab。咱們但願知道一個N位字符串S的前綴是否具備循環節。換言之,對於每 一個從頭開始的長度爲 i (i>1)的前綴,是否由重複出現的子串A組成,即 AAA…A (A重複出 現K次,K>1)。若是存在,請找出最短的循環節對應的K值(也就是這個前綴串的全部可能重複節 中,最大的K值)。
輸入:輸入包括多組測試數據,每組測試數據包括兩行。
第一行輸入字符串S的長度N。
第二行輸入字符串S。
輸入數據以只包括一個0的行做爲結尾。
輸出:對於每組測試數據,第一行輸出 「Test case #」 和測試數據的編號。
接下來的每一行,輸出具備循環節的前綴的長度i和其對應K,中間用一個空格隔開。
前綴長度須要升序排列。
在每組測試數據的最後輸出一個空行。
#include<stdio.h> #include<string.h> const int maxn = 1000000 + 5; char pat[maxn]; int next[maxn]; int len; void getnext() { int i = 0, j = -1; next[0] = -1; while (i < len) { if (j == -1 || pat[i] == pat[j]) { i++, j++; next[i] = j; } else j = next[j]; } } int main() { int t = 0; while (scanf("%d", &len) != EOF && len) { memset(pat, '\0', sizeof(pat)); scanf("%s", pat); getnext(); printf("Test case #%d\n", ++t); for (int i = 2; i <= len; i++) { if (!(i % (i - next[i])) && i / (i - next[i]) != 1) printf("%d %d\n", i, i / (i - next[i])); } printf("\n"); } return 0; }
理解了怎麼得到前綴數組,那麼咱們來淺談KMP的匹配模式:
假設如今文本串S匹配到 i 位置,模式串P匹配到 j 位置
若是j = -1,或者當前字符匹配成功(即S[i] == P[j]),都令i++,j++,繼續匹配下一個字符;
若是j != -1, 且當前字符串匹配失敗(即s[i] != p[i]),則令i不變,j = next[j] 。此時意味着匹配失敗,模板串pat相對於主串str向右移 j-next[j]。
void KMP() { GetNext(pat); int i = 0, j = 0; int sum = 0; while (i < m) //m爲主串str長度 { if (j == -1 || str[i] == pat[j]) i++, j++; else j = Next[j]; if (j == n) //當前模板串pat與主串str其中一部分匹配成功 //根據題意添加條件 } return ; }