KMP算法
为了解决字符串匹配问题
给你两个字符串,寻找其中一个字符串是否包含另一个字符串,如果包含,返回包含的起始位置。
1 //str为子串 2 //prt为母串 3 4 5 void cal_next(char *str, int *next, int len) 6 { 7 next[0] = -1;//next[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀 8 int k = -1;//k初始化为-1 9 for (int q = 1; q <= len-1; q++) 10 { 11 while (k > -1 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。 12 { 13 k = next[k];//往前回溯 14 } 15 if (str[k + 1] == str[q])//如果相同,k++ 16 { 17 k = k + 1; 18 } 19 next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q] 20 } 21 } 22 23 int KMP(char *str, int slen, char *ptr, int plen) 24 { 25 int *next = new int[plen]; 26 cal_next(ptr, next, plen);//计算next数组 27 int k = -1; 28 for (int i = 0; i < slen; i++) 29 { 30 while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配) 31 k = next[k];//往前回溯 32 if (ptr[k + 1] == str[i]) 33 k = k + 1; 34 if (k == plen-1)//说明k移动到ptr的最末端 35 { 36 //cout << "在位置" << i-plen+1<< endl; 37 //k = -1;//重新初始化,寻找下一个 38 //i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在两个匹配字符串可以部分重叠),感谢评论中同学指出错误。 39 return i-plen+1;//返回相应的位置 40 } 41 } 42 return -1; 43 }
模板:
1 #include<stdio.h> 2 #include<string.h> 3 void makeNext(const char P[],int next[]) 4 { 5 int q,k; 6 int m = strlen(P); 7 next[0] = 0; 8 for (q = 1,k = 0; q < m; ++q) 9 { 10 while(k > 0 && P[q] != P[k]) 11 k = next[k-1]; 12 if (P[q] == P[k]) 13 { 14 k++; 15 } 16 next[q] = k; 17 } 18 } 19 20 int kmp(const char T[],const char P[],int next[]) 21 { 22 int n,m; 23 int i,q; 24 n = strlen(T); 25 m = strlen(P); 26 makeNext(P,next); 27 for (i = 0,q = 0; i < n; ++i) 28 { 29 while(q > 0 && P[q] != T[i]) 30 q = next[q-1]; 31 if (P[q] == T[i]) 32 { 33 q++; 34 } 35 if (q == m) 36 { 37 printf("Pattern occurs with shift:%d\n",(i-m+1)); 38 } 39 } 40 } 41 42 int main() 43 { 44 int i; 45 int next[20]={0}; 46 char T[] = "ababxbababcadfdsss"; 47 char P[] = "abcdabd"; 48 printf("%s\n",T); 49 printf("%s\n",P ); 50 // makeNext(P,next); 51 kmp(T,P,next); 52 for (i = 0; i < strlen(P); ++i) 53 { 54 printf("%d ",next[i]); 55 } 56 printf("\n"); 57 58 return 0; 59 }
KMP求子串出现的次数
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 const int MAXW=10001,MAXT=1000001; 6 char W[MAXW],T[MAXT]; 7 int next[MAXW]; 8 int lenW,lenT; 9 10 void getnext(int lenW) 11 { 12 int i=0,j=-1; 13 next[i]=-1; 14 while(i<lenW) { 15 if(j==-1||W[i]==W[j]) { 16 next[++i]=++j; 17 } 18 else j=next[j]; 19 } 20 } 21 22 int kmp(int pos,int lenW,int lenT) 23 { 24 int i=pos,j=0,ans=0; 25 while(i<lenT) { 26 if(T[i]==W[j]||j==-1) ++i,++j; 27 else j=next[j]; 28 if(j==lenW) { 29 ans++; 30 j=next[j-1]; 31 i--; 32 } 33 } 34 return ans; 35 } 36 37 38 int main() 39 { 40 int n; 41 scanf("%d",&n); 42 while(n--) { 43 scanf("%s%s",W,T); 44 lenW=strlen(W); 45 lenT=strlen(T); 46 getnext(lenW); 47 printf("%d\n",kmp(0,lenW,lenT)); 48 } 49 return 0; 50 }