KMP算法:
一:next数组:next[i]就是前面长度为i的字符串前缀和后缀相等的最大长度,也即索引为i的字符失配时的前缀函数。
二:KMP模板
1 /* 2 pku3461(Oulipo), hdu1711(Number Sequence) 3 这个模板 字符串是从0开始的 4 Next数组是从1开始的 5 */ 6 #include <iostream> 7 #include <cstring> 8 using namespace std; 9 10 const int maxn = 1000002; 11 int _next[maxn]; 12 char S[maxn], T[maxn]; 13 int slen, tlen; 14 15 void getNext() 16 { 17 int j, k; 18 j = 0; k = -1; _next[0] = -1; 19 while(j < tlen) 20 if(k == -1 || T[j] == T[k]) 21 _next[++j] = ++k; 22 else 23 k = _next[k]; 24 } 25 26 /* 27 } 28 返回模式串T在主串S中首次出现的位置 29 返回的位置是从0开始的。 30 */ 31 int KMP_Index() 32 { 33 int i = 0, j = 0; 34 getNext(); 35 36 while(i < slen && j < tlen) 37 { 38 if(j == -1 || S[i] == T[j]) 39 { 40 i++; j++; 41 } 42 else 43 j = _next[j]; 44 } 45 if(j == tlen) 46 return i - tlen; 47 else 48 return -1; 49 } 50 /* 51 返回模式串在主串S中出现的次数 52 */ 53 int KMP_Count() 54 { 55 int ans = 0; 56 int i, j = 0; 57 if(slen == 1 && tlen == 1) 58 { 59 if(S[0] == T[0]) 60 return 1; 61 else 62 return 0; 63 } 64 getNext(); 65 for(i = 0; i < slen; i++) 66 { 67 while(j > 0 && S[i] != T[j]) 68 j = _next[j]; 69 if(S[i] == T[j]) 70 j++; 71 if(j == tlen) 72 { 73 ans++; 74 j = _next[j]; 75 } 76 } 77 return ans; 78 } 79 int main() 80 { 81 82 int TT; 83 int i, cc; 84 cin>>TT; 85 while(TT--) 86 { 87 cin>>S>>T; 88 slen = strlen(S); 89 tlen = strlen(T); 90 cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl; 91 cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl; 92 } 93 return 0; 94 }
三:KMP最小循环节、循环周期:
定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。
(1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。
(2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。
学习博客 https://www.cnblogs.com/chenxiwenruo/p/3546457.html
https://www.cnblogs.com/c-cloud/p/3224788.html
循环节例题
题目链接 https://vjudge.net/problem/UVALive-3026
解析 每个前缀的最小循环节 KMP跑一边判断能不能整除就可以了
AC代码
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define F first 5 #define S second 6 #define all(a) (a).begin(), (a).end() 7 #define fillchar(a, x) memset(a, x, sizeof(a)) 8 #define huan printf("\n"); 9 using namespace std; 10 typedef long long ll; 11 const int maxn=1e6+10,inf=0x3f3f3f3f; 12 const ll mod=1e9+7; 13 char p[maxn]; 14 int f[maxn]; 15 int main() 16 { 17 int n,kase=0; 18 while(scanf("%d",&n)==1&&n) 19 { 20 scanf("%s",p); 21 f[0]=0,f[1]=0; 22 for(int i=1;i<n;i++) 23 { 24 int j=f[i]; 25 while(j&&p[i]!=p[j]) j=f[j]; 26 f[i+1]=(p[i]==p[j]?j+1:0); 27 } 28 printf("Test case #%d\n", ++kase); 29 for(int i=2;i<=n;i++) 30 { 31 if(f[i]>0&&i%(i-f[i])==0) 32 printf("%d %d\n",i,i/(i-f[i])); 33 } 34 huan; 35 } 36 }
原文地址:https://www.cnblogs.com/stranger-/p/9395397.html
时间: 2024-10-18 12:23:28