第一题,很简单的板子题,只需要把char 改成int类型就好了
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1000005; int Next[N]; int S[N], T[N]; int slen, tlen;//注意每次一定要计算长度 void getNext() { int j, k; j = 0; k = -1; Next[0] = -1; while(j < tlen) if(k == -1 || T[j] == T[k]) Next[++j] = ++k; else k = Next[k]; } int KMP_Index() { int i = 0, j = 0; getNext(); while(i < slen && j < tlen) { if(j == -1 || S[i] == T[j]) { i++; j++; } else j = Next[j]; } if(j == tlen) return i - tlen+1; else return -1; } int main() { int TT; int i, cc; scanf("%d",&TT); while(TT--) { int i,j,m,n; scanf("%d%d",&n,&m); for(i=0;i<n;i++) { scanf("%d",&S[i]); } for(j=0;j<m;j++) { scanf("%d",&T[j]); } slen = n; tlen = m; printf("%d\n",KMP_Index()); } return 0; }
第二题,仍然为板子题,求母串里有几个子串
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1000005; int Next[N]; char S[N], T[N]; int slen, tlen;//注意每次一定要计算长度 void getNext() { int j, i,k; j = 0; k = -1; Next[0] = -1; while(j < tlen) if(k == -1 || T[j] == T[k]) { Next[++j] = ++k; } else { k = Next[k]; } } int KMP_Count() { int ans = 0; int i, j = 0; if(slen == 1 && tlen == 1) { if(S[0] == T[0]) return 1; else return 0; } getNext(); for(i = 0; i < slen; i++) { while(j>=0 && S[i] != T[j]) j = Next[j]; if(j==-1||S[i] == T[j]) j++; if(j == tlen) { ans++; j = Next[j]; } } return ans; } int main() { int TT; int i, cc; scanf("%d",&TT); while(TT--) { scanf("%s",T); scanf("%s",S); slen = strlen(S); tlen = strlen(T); printf("%d\n",KMP_Count()); } return 0; }
第三题,仍然板子,但是要注意,这里不能重复使用,所以当j==tlen时,j不再等于
Next[j]而是直接等于0;
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1000005; int Next[N]; char S[N], T[N]; int slen, tlen;//注意每次一定要计算长度 void getNext() { int j, i,k; j = 0; k = -1; Next[0] = -1; while(j < tlen) if(k == -1 || T[j] == T[k]) { Next[++j] = ++k; } else { k = Next[k]; } } int KMP_Count() { int ans = 0; int i, j = 0; if(slen == 1 && tlen == 1) { if(S[0] == T[0]) return 1; else return 0; } getNext(); for(i = 0; i < slen; i++) { while(j>=0 && S[i] != T[j]) j = Next[j]; if(j==-1||S[i] == T[j]) j++; if(j == tlen) { ans++; j = 0; } } return ans; } int main() { int TT; int i, cc; while(scanf("%s",S)!=EOF) { if(S[0]=='#') break; scanf("%s",T); slen = strlen(S); tlen = strlen(T); printf("%d\n",KMP_Count()); } return 0; }
第4题,kmp中next数组的应用,主要是找循环节的大小,最少在后面加几个字符才能使其成为循环
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1000002; int Next[N]; char a[N]; int slen, tlen; void getNext() { int j, k; j = 0; k = -1; Next[0] = -1; while(j < tlen) if(k == -1 || a[j] == a[k]) Next[++j] = ++k; else k = Next[k]; } int main() { int i,j,m,n; int t; scanf("%d",&t); while(t--) { scanf("%s",a); tlen=strlen(a); getNext(); j=tlen-Next[tlen]; if(tlen%j==0&&j!=tlen)//注意j==tlen的情况,即他本身就是一个循环节 printf("0\n"); else { printf("%d\n",j-Next[tlen]%j);//注意%j因为像abcabcab中next最后一个为5 } } return 0; }