hdu3068

题意:给出一个字符串,计算其中的最长回文长度

这题字符串长度给到10的5次方,简单的枚举不行。采用manacher算法则可以在O(n)的时间内得出答案。

manacher算法理解:

工具:1、定义了一个数组 r[ i ] 记录的是以i为中心向最左边(或者最右边)的最长回文长度,即回文的半径。

           2、定义整数形的id,记录到目前为止记录的回文所能到的最右边的回文中心。

           3、定义一个maxlen记录最长回文长度

 预处理:在原来的字符串中插入“#”;作用:使插入后的字符串变成奇数长度,便于求出回文中心。

 分析:

 1、i < r [ id ] + id;

    此时分两种:

    1 、r [ i ] = r [ j ]  ( j 为 i 关于 id 的对称点 );

     2、r [ i ] 最小为 r [ id ] +id-i;

  再左右遍历;

 2、i >=r [ id ]+ id;

    这时只能左右遍历了。

 https://www.cnblogs.com/z360/p/6375514.html

具体在这个博客有更详细的分析。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
using namespace std;
#define MAX 110002
int r[2*MAX];
string s,ss;
int init()
{
   int len=s.size();
   ss+='!';//防止溢出
    ss+='#';
   for(int i=0;i<len;i++)
   {
      ss+=s[i];
      ss+='#';
   }
  cout<<ss;
    return ss.size();
}
int manacher(int len)
{
        int id=0;
        int maxlen=0;
     for(int i=2;i<len;i++)
     {
         if(i<r[id]+id)
            r[i]=min(r[2*id-i],r[id]+id-i);
         else
            r[i]=1;
         while(ss[i+r[i]]==ss[i-r[i]])r[i]++;
         if(r[i]+i>r[id]+id)id=i;
         maxlen=max(maxlen,r[i]);
     }
     return maxlen-1;//记得减一
}
int main()
{
  while(cin>>s)
  {
    memset(r,0,sizeof(r));
    ss="";
     int len=init();
    printf("%d\n",manacher(len));
    getchar();
  }
}
View Code

 

posted @ 2018-05-11 21:45  better46  阅读(168)  评论(0编辑  收藏  举报