题目1 : 最长回文子串(Manacher算法--O(n)回文子串算法)

来源:互联网 发布:广告公司开单软件 编辑:程序博客网 时间:2024/06/04 18:34

题目1 : 最长回文子串

时间限制:1000ms
单点时限:1000ms
内存限制:64MB

描述

   小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。

   这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”

   小Ho奇怪的问道:“什么叫做最长回文子串呢?”

   小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”

   小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?

   小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”

样例输入
3abababaaaaabaaacacdas
样例输出
753
#include<stdio.h>#include<string.h>#include<iostream>using namespace std;char str[2000020],s[2000020];int p[2000020];int len,id,mx;void pre() //对字符串进行预处理{  len=strlen(s);  str[0]='$';  str[1]='#';  for(int i=0;i<len;i++)  {    str[i*2+2]=s[i];    str[i*2+3]='#';  }  len=len*2+2;  str[len]=0;}void Manacher() //算法核心{  mx=0;  for(int i=1;i<len;i++)  {    if(mx>i)      p[i]=min(p[2*id-i],p[id]+id-i);    else      p[i]=1;    while(str[i+p[i]]==str[i-p[i]])      p[i]++;    if(p[i]+i>mx)    {      mx=p[i]+i;      id=i;    }  }}int main(){  int N;  scanf("%d",&N);  for(int i=1;i<=N;i++)  {    scanf("%s",s);    pre();    Manacher();    printf("%d\n",p[max_element(p,p+len)-p]-1);  }  return 0;}
  算法大致过程是这样。先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子,回文串长度全为奇数了),然后用一个辅助数组P记录以每个字符为中心的最长回文串的信息。Pid]记录的是以字符strid]为中心的最长回文串,当以strid]为第一个字符,这个最长回文串向右延伸了Pid]个字符。
    原串:    w aa bwsw f d
    新串:   # w# a # a # b# w # s # w # f # d #
辅助数组P:  1 2 1 2 3 2 1 2 1 2 1 4 1 2 1 2 1 2 1
    这里有一个很好的性质,Pid-1就是该回文子串在原串中的长度(包括‘#’)


0 0
原创粉丝点击