最长回文子串-Manacer算法
来源:互联网 发布:淘宝怎么才能搜到黄盘 编辑:程序博客网 时间:2024/06/11 04:24
一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的为回文串的子串。很容易想到暴力的解法,一个一个枚举回文串的起始位置。
#include<cstdio>#include<cstring>#include<iostream>using namespace std;char str[1000010];int main(){int n;cin>>n;while(n--){memset(str,0,sizeof(str));cin>>str;int ans;int i,j,k;bool flag;int len=strlen(str)-1;for(i=len;i>=0;i--){for(j=0;j<=len;j++){k=j+i;if(k<=len){flag=1;int k1=k;int j1=j;while(k1>j1){if(str[k1]!=str[j1]) flag=0;k1--;j1++;}if(flag) {ans=i+1;goto end;}}}}end:cout<<ans<<endl;}}在这个算法中存在大量重复的计算。如果一个字符串的[3, 7]这一段已经不是回文子串了,[2, 8]这一段就不可能是回文子串了。我们可以对这个算法进行改进,枚举回文串的中点,从中点向两边扩展。值得注意的是回文串有奇数长和偶数长两种情况,对于这两种情况我们要分别进行讨论。
#include<cstdio>#include<cstring>#include<iostream>using namespace std;char str[1000010];int main(){int n;cin>>n;while(n--){memset(str,0,sizeof(str));cin>>str;int ans;int i,j,k,maxans=1;bool flag;int len=strlen(str)-1;//回文串的长度是奇数 for(i=0;i<=len;i++){ans=1;j=i+1;k=i-1;while(j<=len&&k>=0){if(str[k]==str[j]) {k--;j++;ans+=2;}else break;}if(ans>maxans) maxans=ans;}//回文串的长度是奇数for(i=0;i<=len;i++){j=i+1;if(str[i]==str[j]){ans=2;j=j+1;k=i-1;while(j<=len&&k>=0){if(str[k]==str[j]) {k--;j++;ans+=2;}else break;}if(ans>maxans) maxans=ans;}}cout<<maxans<<endl;}}下面该轮到我们要隆重介绍的Manacer算法登场了。前面我们说过枚举回文串的中点需要分情况讨论,如果在原来的字符串的前后以及每两个字符之间添加'#'字符(前提是这个'#'不在原串中出现过),显然现在所有的回文串的长度都是奇数的,这样就不用分情况讨论了,这是这个算法非常精妙的地方。我们还需要一个辅助数组p记录以每个字符为核心的最长回文字符串半径。p[i]最小为1,此时回文字符串就是字符串本身。 举个例子:
原来的串:waabwswfd
现在的串:#w#a#a#b#w#s#w#f#d#
辅助数组:1212321212141212121
注意到,P[i]-1就是该回文子串在原串中的长度。接下来就是最关键的部分了。设id的回文串的半径是r[id],那么此时id的回文串右边要延展到right=id+r[id]-1这个字符。在计算(id, right]中的某个点x的时候,可以发现x的关于id的对称点x'=2*id-x的回文串是已经计算过的,利用x'的回文的性质,我们计算x的半径的时候,就不用从1开始枚举,而是从min(r[x'], right-x+1)开始枚举。整个过程中采用贪心法,也就是说选取right尽可能大的id使得后面的中心尽量少的扩展。自己动手画个图就很好理解了。
POJ3974就是这样的一道模板题,贴上AC代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int MAX=1000010; char s[MAX]; char ss[MAX<<1]; int p[MAX<<1]; int solve(int len) { int ans=0; int right=-1; int id=-1; for(int i=0;i<len;i++) { int r=1; if(right>=i) r=max(r,min(right-i+1,p[2*id-i])); while((i-r+1>=0&&i+r-1<len)&&(ss[i-r+1]==ss[i+r-1])) r++; r--; if(i+r-1>right) { right=i+r-1; id=i; } p[i]=r; if(ans<r) ans=r; } return ans-1; } int main() { int Case=1; while(scanf("%s",s)!=EOF) { if(strcmp(s,"END")==0) break; int len=strlen(s); int cnt=0; for(int i=0;i<len;i++) { ss[cnt++]='#'; ss[cnt++]=s[i]; } ss[cnt++]='#'; printf("Case %d: %d\n",Case++,solve(cnt)); } }
0 0
- 最长回文子串-Manacer算法
- hdu3068--最长回文(Manacer算法)
- 最长回文子串算法
- 【算法】最长回文子串
- 算法---最长回文子串
- hdu 3068 最长回文(最长回文子串 manacher算法)
- 【最长回文子串】HDU3068最长回文【Manacher算法】
- 最长回文子串o(n)算法
- Manacher算法求最长回文子串
- Manacher算法求最长回文子串
- 最长回文子串(Manacher算法)
- Manacher算法 最长回文子串
- 最长回文子串的manacher算法
- 最长回文子串,Manacher算法
- Poj3974 最长回文子串 Manacher算法
- 最长回文子串 manacher算法
- Manacher算法(最长子回文串)
- hihocoder1032(最长回文子串manacher算法)
- 知乎小报开发总结
- Android基础第一节课
- JS实现数的遍历,查询,增加节点,删除节点
- iOS 集成环信(一)
- c++常量
- 最长回文子串-Manacer算法
- OpenCV:对XML和YAML文件实现I/O操作
- 页面布局之双飞翼布局
- 使用引用形参返回额外信息
- c++作业4
- C++上级实验4-求1000以内所有偶数的和
- POJ 1042 Gone Fishing(模拟+贪心)
- 深拷贝与浅拷贝
- Leetcode 1, Two Sum