kmp处理题型总结
1.求出T(模板串)对S(原串)的最小完全匹配位置 HDU-1711 Number Sequence (普通kmp)
2.求T(模板串)在S(原串)中出现的次数(可以重复匹配) POJ-3461 Oulipo (kmp修改)
3.求T(模板串)在S(原串)出现的次数(不可重复匹配)HDU-2087 剪花布条
4.求字符串S的最小的循环节 HDU-3746 Cyclic Nacklace ,HDU-1358 Period (KMP循环节问题) ,POJ-2406 Power Strings
5.找到(输出)字符串S中所有的 公共前后缀 部分 POJ-2752 Seek the Name, Seek the Fame (KMP)
5*.输出 字符串S中所有的 公共前后缀串之和 HDU-3336 Count the string (KMP)
6.找出所给的多个串的相同子串部分 POJ-3080 Blue Jeans (KMP优化匹配)
7.给出两个字符串a,b然后求a前缀与b后缀的最长公共部分 并输出 长度 HDU-2594 Simpsons’ Hidden Talents (kmp) 也可以说是 (扩展kmp)
模板总结:
求某个字符串的next数组 (对于kmp而言)
const int maxn = 1e5+7;
int nex[maxn];char str[maxn]; void getnext(char *str){ int i=0,j=-1; int len = strlen(str); nex[i]=j; while(i<len){ if(j==-1||str[i]==str[j]){ i++;j++; nex[i]=j; } else j=nex[j]; } }
KMP 求最小位置匹配,以及否出现判断(没有出现输出返回-1):
int nex[maxn]; char str[maxn];//文本串 char str1[maxn];//模式串 int kmp(){ int i = 0, j = 0; getnext(str1); int len = strlen(str); int len1 = strlen(str1); while(i < len && j < len1) { if(j == -1 || a[i] == b[j]) { i++; j++; } else j = nex[j]; } return (j==len1)?(i -len1 + 1):-1; }
KMP 求匹配次数
int nex[maxn]; char str[maxn];//文本串 char str1[maxn];//模式串 int kmp(char *str, char *str1){ int ans = 0; int i = 0,j = 0; int len,len1; len = strlen(str),len1 = strlen(str1); if(len == 1 && len1 == 1){ return (str[0] == str1[0]) ? 1 : 0; } getnext(str1); for(i=0;i<len;i++){ while( j>0 && str[i]!=str1[j] ){ j=nex[j]; } if(str[i] == str1[j]) j++; if(j==len1){ ans++; j=nex[j];//重复统计次数
//j = 0;不重复统计次数 } } return ans; }
KMP 求循环节个数(如果不存在则返回-1)
int loop(char *str){ int len = strlen(str); //nex[len] == 0时必然没有循环节 if(nex[len]!=0){ //循环节长度 int k = len - nex[len]; //如果循环节个数不为0 if(!(len % k)){ //求出循环节个数 int num = len / k; return num; } } else return -1; }
计算某个字符串的所有前缀子串,在字符串出现的次数的总和
例如 s: "abab"
The prefixes are: "a", "ab", "aba", "abab"
The sum = 2 + 2 + 1 + 1 = 6.
//(1)求所有前缀和 int len = strlen(str);//母串
for(int i=1;i<=len;i++){ dp[i]=dp[nex[i]]+1; sum = (sum+dp[i])%mod; }
//(2)回溯 找到所有公共的前缀部分
ans = nex[nex[i]];
求扩展KMP的 extend[]数组:
//str2为模板串,str1为原串(母串)
void getnext(char *str2){ nex[0]=len2; int j=0,p; while(j+1<len1&&str2[j]==str2[j+1])j++; nex[1]=j; int k=1; for(int i=2;i<len2;i++){ p=nex[k]+k-1; if(i+nex[i-k]-1<p) nex[i]=nex[i-k]; else{ j = max(0,p-i+1); while(i+j<len2&&str2[i+j]==str2[j])j++; nex[i]=j; k=i; } } } void exkmp(char *str1,char *str2){ getnext(); int j=0,p; int len = min(len1,len2); while(j<len&&str2[j]==str1[j])j++; extend[0]=j; int k=0; for(int i=1;i<len1;i++){ p = extend[k]+k-1; if(i+nex[i-k]-1<p) extend[i]=nex[i-k]; else{ j=max(0,p-i+1); while(i+j<len1&&j<len1&&str1[i+j]==str2[j])j++; extend[i]=j; k=i; } } }