练习:点击打开链接
字符串也是ACM中的重头戏,基本内容有KMP ,扩展KMP, Manacher ,AC自动机,后缀数组,后缀自动机.按照专题来做共分三部分. LCS LIS LCIS不知道算不算....点击打开链接
小技巧:匹配问题不区分大小写,则将其全部转为小写.
暴力匹配: 用strstr函数就能解决 I M N Z(枚举长度 三份)
一.KMP算法
解决单一模式串匹配问题.
利用失配后的nxt数组减少移位,达到O(n)级别.资料自行百度.
延展:
1.求最小循环节 点击打开链接 就是len-nxt[len] D E(这个题目意思是i为止可以表示成循环的字符) F G
2.求各个循环节 P(先求出最小循环节,然后进入nxtval[i]再求最小循环节累加就是第二小依次循环)
3.字符串最大最小表示法 O(最大最小 循环长度就是最小循环节) P(都转为最小 map存放)
4.模式串成功匹配次数(可以有重叠) 匹配成功后j=nxt[j] B
5.模式串成功匹配次数(不能有重叠) 匹配成功后j=0 C
6.既是前缀又是后缀 用nextval递归往后 H
7.一个串的最长前缀另一个串的最长后缀,连起来求nxt 完了判断最长的不要大于字符串长就行
8.各种前缀可匹配的次数 自左至右计算nxt[]的dp[] ,dp[i]=dp[nxt[i]]+1 ans+=dp[i]
9.
二.扩展KMP
求extand[] 表示以i起始的后缀串与模式串匹配的长度.nxt[] 表示以i起始模式串的后缀串与模式串匹配的长度 点击打开链接
1.利用nxt数组求最长后缀串匹配长度 裸EXKMP L
三.最长回文
一个串中最长的连续回文.p[i] 以i为中点的最长回文数.点击打开链接
U V W X
其中V是吉哥系列2要求连续 规模10^5,有个要求是大于等于,所以加个限制条件就行 系列1使用的是LCS,不要求连续规模10^2
不要求连续的回文使用转置再求LCS (HDU1513 点击打开链接)
///核心思想是利用之前已经"匹配"信息减少j移动 ///EXKMP方法是记录一个最远匹配位置 ///KMP void getnxt(){ int j = -1; nxt[0] = -1; for(int i = 0;i < M;){ if(j == -1 || s2[i] == s2[j]){ i++,j++; if(s2[i] == s2[j]) nxt[i] = nxt[j]; else nxt[i] = j; } else j = nxt[j]; } } int KMP(){ getnxt(); int i = 0,j = 0; while(i < N){ ///这个写错了,不是字符串\0的意思 if(j == -1 || s1[i] == s2[j]) i++,j++; else j = nxt[j]; if(j==M) return i-M+1; } return -1; } ///EXKMP void Getnxt(const char *T){ int len=strlen(T),a=0; nxt[0]=len; while(a<len-1 && T[a]==T[a+1]) a++; nxt[1]=a; a=1; for(int k=2;k<len;k++){ int p=a+nxt[a]-1,L=nxt[k-a]; if( (k-1)+L >= p){ int j = (p-k+1)>0 ? (p-k+1) : 0; while(k+j<len && T[k+j]==T[j]) j++; nxt[k]=j; a=k; } else nxt[k]=L; } } void GetExtand(const char *S,const char *T){ Getnxt(T); int slen=strlen(S),tlen=strlen(T),a=0; int MinLen = slen < tlen ? slen : tlen; while(a<MinLen && S[a]==T[a]) a++; extand[0]=a; a=0; for(int k=1;k<slen;k++){ int p=a+extand[a]-1, L=nxt[k-a]; if( (k-1)+L >= p){ int j= (p-k+1) > 0 ? (p-k+1) : 0; while(k+j<slen && j<tlen && S[k+j]==T[j]) j++; extand[k]=j; a=k; } else extand[k]=L; } }
/** 最长回文子串,求的是连续.如果可以不连续则reserve再LCS http://blog.csdn.net/xingyeyongheng/article/details/9310555 **/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define maxn 150000 char fst[maxn]; char sed[2*maxn+2]; int p[2*maxn+2]; int Manacher(){ int len = strlen(fst); int maxlen =0,id=0; for(int i = 0;i < len;i++){ sed[i*2+1] = '#'; sed[i*2+2] = fst[i]; } sed[2*len+1] = '#'; sed[2*len+2] = 0; sed[0] = '@'; len = 2*len+1; for(int i = 2;i < len;i++){ if(p[id] + id > i) p[i] = min(p[2*id-i],p[id]+id-i); else p[i] = 1;///公式化简一下 k=i-id i-k=2id-i while(sed[i-p[i]] == sed[i+p[i]]) ++p[i];///害怕这里越界 if(id+p[id]<i+p[i]) id=i;///i+p[id] 这个写错了....我擦 maxlen = max(maxlen,p[i]); } return maxlen-1; } int main(){ while(~scanf("%s",fst)) printf("%d\n",Manacher()); return 0; }