KMP演算法模板
阿新 • • 發佈:2021-01-20
概述
模板出自kuangbin的部落格
典型應用:
給你兩個字串,尋找其中一個字串是否包含另一個字串,如果包含,返回包含的起始位置。
(1) 標頭檔案
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5+10; 4 int Next[N]; 5 char S[N],T[N]; // S:主串 T:模式串 6 int slen,tlen;
(2) getNext()函式
1 void getNext() 2 { 3 int j,k; 4 j = 0; k = -1; Next[0] = -1; 5 while(j < tlen) 6 { 7 if(k == -1 || T[j] == T[k]) 8 Next[++j] = ++k; 9 else 10 k = Next[k]; 11 } 12 }
(3) 返回模式串T在主串S中首次出現的位置
1 // 返回模式串T在主串S中首次出現的位置 2 // 返回的位置是從0開始的 3 int KMP_Index() 4 { 5 int i = 0,j = 0; 6 getNext();7 8 while(i < slen && j < tlen) 9 { 10 if(j == -1 || S[i] == T[j]) 11 { 12 i++; j++; 13 } 14 else 15 j = Next[j]; 16 } 17 if(j == tlen) 18 return i-tlen; 19 else 20 return -1; 21 }
(4) 返回模式串在主串S中出現的次數
1 int KMP_Count() 2 { 3 int ans = 0; 4 int i,j = 0; 5 6 if(slen == 1 && tlen == 1) 7 { 8 if(S[0] == T[0]) 9 return 1; 10 else 11 return 0; 12 } 13 getNext(); 14 for(i = 0;i < slen;i++) 15 { 16 while(j > 0 && S[i] != T[j]) 17 j = Next[j]; 18 if(S[i] == T[j]) 19 j++; 20 if(j == tlen) 21 { 22 ans++; 23 j = Next[j]; 24 } 25 } 26 return ans; 27 }
(5) 全家福
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 /***************KMP***************/ 5 const int N = 1e5+10; 6 int Next[N]; 7 char S[N],T[N]; // S:主串 T:模式串 8 int slen,tlen; 9 10 void getNext() 11 { 12 int j,k; 13 j = 0; k = -1; Next[0] = -1; 14 while(j < tlen) 15 { 16 if(k == -1 || T[j] == T[k]) 17 Next[++j] = ++k; 18 else 19 k = Next[k]; 20 } 21 } 22 23 // 返回模式串T在主串S中首次出現的位置 24 // 返回的位置是從0開始的 25 int KMP_Index() 26 { 27 int i = 0,j = 0; 28 getNext(); 29 30 while(i < slen && j < tlen) 31 { 32 if(j == -1 && S[i] == T[j]) 33 { 34 i++; j++; 35 } 36 else 37 j = Next[j]; 38 } 39 if(j == tlen) 40 return i-tlen; 41 else 42 return -1; 43 } 44 45 // 返回模式串在主串S中出現的次數 46 int KMP_Count() 47 { 48 int ans = 0; 49 int i,j = 0; 50 51 if(slen == 1 && tlen == 1) 52 { 53 if(S[0] == T[0]) 54 return 1; 55 else 56 return 0; 57 } 58 getNext(); 59 for(i = 0;i < slen;i++) 60 { 61 while(j > 0 && S[i] != T[j]) 62 j = Next[j]; 63 if(S[i] == T[j]) 64 j++; 65 if(j == tlen) 66 { 67 ans++; 68 j = Next[j]; 69 } 70 } 71 return ans; 72 } 73 /***************END***************/ 74 75 int main() 76 { 77 int TT; 78 cin >> TT; 79 while(TT--) 80 { 81 cin >> S >> T; 82 slen = strlen(S); 83 tlen = strlen(T); 84 cout << "模式串T在主串中首次出現的位置是: " << KMP_Index() << endl; 85 cout << "模式串T在主串S中出現的次數為: " << KMP_Count() << endl; 86 } 87 return 0; 88 }View Code
(6) 補充
KMP的優化
1 void getNext() 2 { 3 int j,k; 4 j = 0,k = -1,Next[0] = -1; 5 while(j < tlen) 6 { 7 if(k == -1 || T[j] == T[k]) 8 { 9 j++,k++; 10 if(T[j] == T[k]) 11 Next[j] = Next[k]; // 直接走到下一個不相等的地方 12 else 13 Next[j] = k; 14 } 15 else 16 k = Next[k]; 17 } 18 }
Next[]陣列求迴圈節
性質:
- len-next[i]為此字串的最小迴圈節(i為字串的結尾)
- 另外如果len%(len-next[i])==0,此字串的最小週期就為len/(len-next[i])
- 如果len%(len-next[i]) != 0 則沒有迴圈節???(小聲逼逼)