参考:https://blog.csdn.net/qq_30241305/article/details/50700199
A.更正后模板代码,求子串最初出现位置
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int nexta[10005],a[1000005],s[10005]; 6 int n,m; 7 void getnexta(int s[])//初始next数组 8 { 9 memset(nexta,0,sizeof(nexta)); 10 int k = -1,j = 0; 11 nexta[0] = -1; 12 13 while(j <m)//这里的m为全局变量,为模式串长度 14 { 15 16 if(k == -1 || s[k] == s[j]) 17 { 18 nexta[j + 1] = k + 1; 19 j ++; 20 k ++; 21 } 22 else 23 { 24 k = nexta[k]; 25 } 26 } 27 28 } 29 int kmp(int s[],int t[])//t模式串,s母串 30 { 31 getnexta(t); 32 33 int i = 0,j = 0; 34 while(i < n && j < m) 35 { 36 if(j == -1 || s[i] == t[j]) 37 { 38 i ++; 39 j ++; 40 } 41 else 42 { 43 j = nexta[j]; 44 } 45 if(j == m) 46 { 47 return i - j+ 1;//匹配开始位置 48 } 49 } 50 return -1; 51 } 52 int main() 53 { 54 // freopen("in.txt","r",stdin); 55 int T; 56 scanf("%d",&T); 57 while(T--) 58 { 59 scanf("%d%d",&n,&m); 60 for(int i = 0;i < n; i ++) 61 { 62 scanf("%d",&a[i]); 63 } 64 for(int j = 0; j < m;j ++) 65 { 66 scanf("%d",&s[j]); 67 } 68 printf("%d ",kmp(a,s)); 69 } 70 return 0; 71 }
B.较好的模板,求字串出现次数,可重叠
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int nexta[1000006]; 6 char t[1000006],s[1000006]; 7 void getnexta(char s[]) 8 { 9 memset(nexta,0,sizeof(nexta)); 10 int n = strlen(s);//这里的s并非为母串,而要看传入的数组! 11 int k = -1,j = 0; 12 nexta[0] = -1; 13 while(j <n) 14 { 15 16 if(k == -1 || s[k] == s[j]) 17 { 18 nexta[j + 1] = k + 1; 19 j ++; 20 k ++; 21 } 22 else 23 { 24 k = nexta[k]; 25 } 26 } 27 28 } 29 int kmp(char s[],char t[])//t模式串,s母串. 30 { 31 getnexta(t); 32 int ans = 0; 33 int n = strlen(s),m = strlen(t); 34 int i = 0,j = 0; 35 while(i < n && j < m) 36 { 37 if(j == -1 || s[i] == t[j]) 38 { 39 i ++; 40 j ++; 41 } 42 else 43 { 44 j = nexta[j]; 45 } 46 if(j == m)//根据题目要求改变 47 { 48 ans ++; 49 j = nexta[j]; 50 } 51 } 52 return ans; 53 } 54 int main() 55 { 56 // freopen("in.txt","r",stdin); 57 int T; 58 scanf("%d",&T); 59 while(T--) 60 { 61 scanf("%s%s",t,s); 62 printf("%d ",kmp(s,t)); 63 } 64 return 0; 65 }
C。不能重叠
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int nexta[1006]; 6 char t[1006],s[1006]; 7 void getnexta(char s[]) 8 { 9 memset(nexta,0,sizeof(nexta)); 10 int n = strlen(s); 11 int k = -1,j = 0; 12 nexta[0] = -1; 13 while(j < n ) 14 { 15 16 if(k == -1 || s[k] == s[j]) 17 { 18 nexta[j + 1] = k + 1; 19 j ++; 20 k ++; 21 } 22 else 23 { 24 k = nexta[k]; 25 } 26 } 27 28 } 29 int kmp(char s[],char t[])//t模式串,s母串. 30 { 31 getnexta(t); 32 int ans = 0; 33 int n = strlen(s),m = strlen(t); 34 int i = 0,j = 0; 35 while(i < n && j < m) 36 { 37 if(j == -1 || s[i] == t[j]) 38 { 39 i ++; 40 j ++; 41 } 42 else 43 { 44 j = nexta[j]; 45 } 46 if(j == m)//根据题目要求改变 47 { 48 ans ++; 49 j = 0; 50 } 51 } 52 return ans; 53 } 54 int main() 55 { 56 // freopen("in.txt","r",stdin); 57 while(1) 58 { 59 scanf("%s",s); 60 if(strcmp(s,"#") == 0) 61 break; 62 scanf("%s",t); 63 printf("%d ",kmp(s,t)); 64 } 65 return 0; 66 }
D。最小循环节
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int nexta[100005]; 6 char s[100005]; 7 void getnexta(char s[]) 8 { 9 memset(nexta,0,sizeof(nexta)); 10 int n = strlen(s); 11 int k = -1,j = 0; 12 nexta[0] = -1; 13 while(j < n ) 14 { 15 if(k == -1 || s[k] == s[j]) 16 { 17 nexta[j + 1] = k + 1; 18 j ++; 19 k ++; 20 } 21 else 22 { 23 k = nexta[k]; 24 } 25 } 26 } 27 int main() 28 { 29 // freopen("in.txt","r",stdin); 30 int T,ans,n,temp; 31 scanf("%d",&T); 32 while(T --) 33 { 34 scanf("%s",s); 35 n = strlen(s); 36 getnexta(s); 37 temp = n - nexta[n];//最小循环节,例如s:abcdeabc,则串长n为8,nexta[n]为s[0]到s[7]的 38 if(temp == n)//前,后缀匹配长度为3(abc),所以n-next[n]为8-3=5,即最小循环节长(abcde) 39 { 40 ans = n;//除nexta[0]为-1外,其余nexta值最小为0,此情况为整体字符串为一个循环节 41 } 42 else if(n % temp == 0)//自身已经循环 43 { 44 ans = 0; 45 } 46 else 47 { 48 ans = temp - (n % temp); 49 } 50 printf("%d ",ans); 51 } 52 return 0; 53 }
G.
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int nexta[1000002]; 6 char s[1000002]; 7 int n; 8 void getnexta() 9 { 10 memset(nexta,0,sizeof(nexta)); 11 int k = -1,j = 0; 12 nexta[0] = -1; 13 while(j < n ) 14 { 15 16 if(k == -1 || s[k] == s[j]) 17 { 18 nexta[j + 1] = k + 1; 19 j ++; 20 k ++; 21 } 22 else 23 { 24 k = nexta[k]; 25 } 26 } 27 28 } 29 int main() 30 { 31 //freopen("in.txt","r",stdin); 32 int ans; 33 while(1) 34 { 35 ans = 0; 36 scanf("%s",s); 37 if(strcmp(s,".") == 0) 38 break; 39 n = strlen(s); 40 getnexta(); 41 if(n % (n - nexta[n]) == 0 )//记住n-nexta[n]为最小循环节长度 42 ans = n / (n - nexta[n]); 43 else 44 ans = 1; 45 printf("%d ",ans); 46 } 47 return 0; 48 } 49 50 51 //ababa
H。题意:https://blog.csdn.net/alongela/article/details/8196915
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int nexta[1000002]; 6 char s[1000002]; 7 int ans[1000002]; 8 int n; 9 void getnexta() 10 { 11 memset(nexta,0,sizeof(nexta)); 12 int k = -1,j = 0; 13 nexta[0] = -1; 14 while(j < n ) 15 { 16 17 if(k == -1 || s[k] == s[j]) 18 { 19 nexta[j + 1] = k + 1; 20 j ++; 21 k ++; 22 } 23 else 24 { 25 k = nexta[k]; 26 } 27 } 28 29 } 30 31 int main() 32 { 33 //freopen("in.txt","r",stdin); 34 int temp,k; 35 while(scanf("%s",s) != EOF) 36 { 37 k = 0; 38 n = strlen(s); 39 getnexta(); 40 temp = n; 41 ans[k] = n; 42 k ++; 43 while(nexta[temp]!= 0)//当nexta[temp]==0说明该字符前的串没有相同前后缀 44 { 45 temp = nexta[temp]; 46 ans[k] = temp; 47 k ++; 48 } 49 for(int i = k -1; i > 0; i --) 50 printf("%d ",ans[i]); 51 printf("%d ",ans[0]); 52 53 } 54 return 0; 55 } 56 57 58 //ababa