最长回文子串-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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 兔子下牙齿断了怎么办 刚种的花蔫了怎么办 鲜切花花朵蔫了怎么办 兔子扭伤脚肿了怎么办 兔子的耳朵肿了怎么办 家里养兔子大了怎么办 幼兔不吃兔粮怎么办 大兔子咬小兔子怎么办 买的小兔子拉稀怎么办 半个月的小兔子怎么办 母兔下崽没奶怎么办 母松鼠下崽后没有奶怎么办 母猫下崽后小猫没奶吃怎么办 母兔产后没奶水怎么办 兔子生崽了不管怎么办 兔子下小兔不管小兔怎么办 兔子下小兔示喂奶怎么办 兔子生完小兔不喂奶怎么办 小兔子生宝宝了怎么办 人摸了小兔崽怎么办 狗狗尿道有脓怎么办 笼养母兔下崽了怎么办 小羊羔站不起来怎么办 兔子不让小兔子吃奶怎么办 兔子不吃东西没精神怎么办 母兔没有初奶怎么办 兔子只喝水不吃东西怎么办 兔子不吃东西也不喝水怎么办 兔子怀孕后不爱吃东西喝水怎么办 母兔产仔无奶怎么办 仔兔十五天母兔没奶怎么办 兔子刚生下兔宝宝该怎么办 兔子不吃草超瘦怎么办 兔子喝水喝多了怎么办 狗吃了变质食物怎么办 狗崽20天没睁眼怎么办 刚生的小狗缺氧怎么办 狗狗生出来了怎么办 刚生的小狗狗死了怎么办 母狗生的死狗怎么办 狗生宝宝都死了奶水怎么办