Manacher算法求最长回文子串

Manacher算法是时间复杂度为O(n)的求最长回文子串的算法

算法的主要思想是从左到右处理字符串,求每个位置为中心的两端对称的最大半径。
由于我们只考虑以每个位置为中心,所以要把字符串转换一下,如字符串babbcaa,转换成@#b#a#b#b#c#a#a#$,这样就可以统一处理了。

void Manacher(char s[],int n,int radius[])

{

      int i,j;

      for(i=1;i<n;i++) radius[i]=1;

      for(i=2;i<n;i=j)

      {

           while(s[i-radius[i]]==s[i+radius[i]]) radius[i]++;  //求以当前位置为中心的最大对称半径

           int rBnd=i+radius[i];

           for(j=i+1;j<rBnd;j++) //对当前位置半径覆盖范围内右边的位置进行处理

           {
                 /*
                 ** 如果位置j以位置i为中心的对称位置k=i-(j-i),它的最大半径被i的半径包含,

                 ** 那么j的最大半径就等于radius[k],根据对称性;
                 ** 否则,也就是位置k的最长回文串的左端等于或者向左超过以i为中心的回文串的左端,

                 ** 那么j的最大半径至少为i+radius[i]-j;
                 ** 这样,i~j中间位置的最大半径都求出来了,i下次直接从j开始扩展最大半径
                 */

                 if(j+radius[i-(j-i)]<rBnd)  

                      radius[j]=radius[i-(j-i)];

                 else

                 {

                      radius[j]=rBnd-j;

                      break;

                 }

           }

      }

}

虽然表面是双重循环,但我们分析一下,由于循环内部是每次从位置i扩展到下一个位置j,一直扩展到位置n,如果把外层循环,一层一层展开接起来,那就是常数倍从1n的运算,所以总起来的运算量是O(n)的。

网上较多的是下面这种写法:

void Manacher(int rad[],char str[],int n)

{

   int i,mx=0,id;

   for(i=1;i<n;i++)

   {

      if(mx>i) rad[i]=min(rad[2*id-i],mx-i);

      else rad[i]=1;

      for(;str[i+rad[i]]==str[i-rad[i]];rad[i]++)

        ;

      if(mx<rad[i]+i)

      {

        mx=rad[i]+i;

        id=i;

      }

   }

}

相关题目:poj 3974

    原文作者:WalkingInTheWind
    原文地址: https://blog.csdn.net/WalkingInTheWind/article/details/8210036
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞