概述
模板出自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 }
(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 则没有循环节???(小声逼逼)