求解字符串的最长回文子串的Manacher’s Algorithm

来源:互联网 发布:jquery ui.min.js下载 编辑:程序博客网 时间:2024/06/11 21:27

Manacher’s Algorithm

Manacher’s Algorithm求解字符串的最长回文子串:这种算法的好处是将处理的时间复杂度降低到了O(n),是一种线性方法;

算法分析:

假设字符串为:GDGFGHJKKJHGFSFFSJFHS;

在任意的两个字符的开头结尾都插入相同字符如:#;结果如下:#G#D#G#F#G#H#J#K#K#J#H#G#F#S#F#F#S#J#F#H#S#

然后我们可以把全新的字符串的下标表示出来从0开始;

#G #D #G# F#G # H # J # K # K # J # H # G # F # S # F #F#S#J#F#H#S#

0 1 2 3 4 5 6 7 8 9 10 ……………..

最后以全新字符串的下标创建一个数组P[];P[n]的值为相对应字符串所对应回文值,比如:P[1]=1、P[2]=0、P[3]=3、P[4]=0;

我们就可以看出数组P中的最大值为最长回文子串的长度,且最大值对应的字符为全新字符串的最长回文串的中心;所以算法的最核心就是求解全新字符串对应的回文数组P[]。(全新字符串长度为n)

求解P[i]分析:如下图所示;


求P[i]: 已知P[i]之前的值,C为回文串的中心,R为以C为中心的回文串的最外沿,其回文半径为R-C;从L到R以C为对称中心,i的对称点为i’。

1、当P[i]<R-i时,P[i] = P[i’];

2、当P[i]>=R-i时,P[i] = R-i ;然后接着遍历R+1和其以i为对称中心的对称点,如果还是满足对称则P[i]加1,然后一直往下遍历直到找到i的最大回文半径即P[i],然后修改对称中心把C移到i处即C = i ;同时把R= P[i]+i;接下来求解P[i+1],然后一直求解到P[n-1];

这样就可以求出来全新字符串对应的回文数组的最大值,也就求出最长回文串的长度。同时也知道最大回文串的对称中心i。

C++ 代码如下:

class Solution {

public:

   string longestPalindrome(string s) {

       string l;

       l = s;

       int r=0,i,n,j=0,i_mirror=0,centre=0;    //对称中心、镜像对称点、回文半径都是0;

       for(i=0;i<=s.size();i++){

            l.insert(l.begin()+2*i,1,'#');  //在每个字符的开头和结尾插入#;

       }

       l.insert(l.begin(),1,'$');    //在全新字符串开头插入$;

       n = l.size();

       int p[n] ;

        for(i=0;i<n-1;i++){              //遍历全新字符串;

            i_mirror = 2*centre-i;    //镜像对称点与对称中心的关系

            p[i] = (r>i) ?min(r-i,p[i_mirror]) : 0;          //遍历是否超出当前回文串;

            while(l[i+p[i]+1]==l[i-p[i]-1]){  //遍历P[i]+1和其以i为对称中心的镜像对称点;

                p[i]++;             //符合条件加一;

            }    

            if(p[i]+i>r){            //符合条件交换对称中心和回文半径;

                    centre = i;

                    r = i + p[i];

                }   

       }

       int max = 0,centre_index = 0;

       for(i = 1;i<n-1;i++){             //求回文数组的最大值和其对称中心;

            if(p[i]>max){

                max = p[i];

                centre_index = i;

            }   

       }

       return s.substr((centre_index-max-1)/2,max);       

   }

};

代码细节:这里为了便于代码的编写对于全新字符串做一下修改,在字符串的最前面加了一个字符$。

阅读全文
1 0
原创粉丝点击