求最大回文子串(Manacher算法)

这个知识点我第一天听时,完全不懂,后来慢慢的看一个pdf文档和请教一个学长才有点懂得,到今天我继续看一篇博客,才对最大回文子串有清晰的理解,所以上面有什么不对的请给位积极指出。

求最大回文子串,我个人觉得其实就是一种想法(它用到了动态规划的思想),还不算一种单独的算法。。。。。。

首先,回文串是一个正读和反读都是一样的字符串,比如abba,abcdadcba等等

回文子串就是在一个字符串中满足回文串概念的一个或者是多个子串(包括它自身)

最简单最直接的想法就是从头到尾遍历,分别以每一个字符为中心向两侧扩展,算出以每一个字符下为中心所包含的回文串的个数(包括自身的)。虽然这种方法很好想,但是它的时间复杂度为O(n^2),这个时间是很低的。

所以,我们就想到了一种只需要O(n)的时间复杂度的方法

用这种方法求最大回文子串,首先需要对原字符串进行预处理,因为在以前求回文串时,需要判断奇偶的情况。预处理就是在一串字符串中每相邻两个字符之间都添加上一个’#’(字符串的最前面和最后面都也要加上一个字符’#’,还有,最前面的最前面的加一个字符是防止在求p[i]时向两边扩展可能引起数组越界)

字符添加好后,最重要的一点就是如何求p[i]数组的值?

首先,p[i]数组表示的含义是,记录的以每一个字符为中心的最长回文串的半径(以每一个字符为中心能组成的回文子串的个数),也就是记录以S[I]为中心的最长的回文子串的半径)

P[i]数组的求法,要借鉴动态规划的思想

举例:求abaab的最大回文子串?



首先,我们先定义两个变量,一个maxid表示在求i之前的回文串中,能延伸到最右端的位置,同时好有一个id记录取这个maxidid

Maxid=p[id]+id

分两种情况:

1、  第i个位置不在前面的任何回文串中,即maxid

2、  如果maxid>i,那么就不是初始化p[i]=1,就要由回文串的性质,在id位置前还应该有一个j位置,它是关于id位置对称。可以对称到i位置

如图:


或者是




其实,就是把它们看成一个一维的坐标来看,j就可以表示成j=2*id-i,由中点坐标公式得来的;如果不用中点坐标公式,可以用几何关系推出来,i-2*i-id);

 

所以,p[i]又可以分出3种情况:

1、以j为中心的回文串的范围有一部分在id为中心的回文串范围之外,所以推出,maxid-i=p[i]-k(k为i和maxid之间的距离)

2、以j为中心的回文串的范围全部在id为中心的回文串范围之内,所以推出,p[i]=p[j]

3、j的回文串的左端部分与id的回文串的左端部分重叠,即j-p[j]=i-p[i],所以p[j]=p[i],并且p[i]可以继续增加,需要while(s[p[i]+i]==s[i-p[i]];p[i]++;这句话来控制


代码:

#include

#include

#include

#include

#include

using namespace std;

const int N=1010;

char s1[N],s2[2*N];

int p[2*N];

void Init(int len)

{

   s2[0]='*',s2[len*2+1]='#';

   for(int i=0;i

    {

       s2[i*2+1]='#';

       s2[i*2+2]=s1[i];

    }

}

int Solve(int len)

{

   int maxid=0,maxl=0,id;

   for(int i=1;i<=len*2+1;i++)

    {

       if(maxid>i)

           p[i]=min(p[2*id-i],maxid-i);

       else

           p[i]=1;

       while(s2[i+p[i]]==s2[i-p[i]])

           p[i]++;

       if(p[i]+i>maxid)

       {

           maxid=p[i]+i;

           id=i;

       }

       if(p[i]>maxl)

           maxl=p[i];

    }

   return maxl-1;

}

int main()

{

   while(~scanf("%s",s1))

    {

       int len=strlen(s1);

       Init(len);

       int l=Solve(len);

       printf("%d\n",l);

    }

   return 0;

}


你可能感兴趣的:(求最大回文子串(Manacher算法))