5_Longest Palindromic Substring(Manacher) --LeetCode

参考:https://www.felix021.com/blog/read.php?2040https://segmentfault.com/a/1190000002991199 做了修改。

  首先用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插入一个特殊的符号。比如 abba 变成 #a#b#b#a#, aba变成 #a#b#a#。 为了进一步减少编码的复杂度,可以在字符串的开始加入另一个特殊字符,这样就不用特殊处理越界问题,比如$#a#b#a#(注意,下面的代码是用C语言写就,由于C语言规范还要求字符串末尾有一个'\0'所以正好OK,但其他语言可能会导致越界)。
下面以字符串12212321为例,经过上一步,变成了 S[] = "$#1#2#2#1#2#3#2#1#";

  原帖中需要用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i],也就是把该回文串“对折”以后的长度),比如S和P的对应关系:

  S  #  1  #  2  #  2  #  1  #  2  #  3  #  2  #  1  #
  P  1  2  1  2  5  2  1  4  1  2  1  6  1  2  1  2  1
  (p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)

 

但我不采用以上的做法,我的算法思想如下:

从S的下标1开始遍历到下标S.length()-2做如下操作

1) 假设偏移量为offset, 用一个while循环控制在对比 S[i-offset] 和第 S[i+offset] 的字符是否相等,每次循环offset自增,直到S[i-offset] 不等于S[i+offset] 或者i-offset<1或者i+offset>S.length()-1跳出循环。

2) 使用一个变量maxlength记录最长回文子串向左/右扩张的长度,以及一个maxidx记录当前最大回文串的中心位置,判断当前的offset与maxlength的大小,取较大赋值给maxlength。

3) 根据maxidx找到最大回文的中心位置,再根据其maxlength计算出回文串的起始位置以及长度。再使用substr()方法将回文串截取出来。如str.substr(maxidx-maxlength+1,2*maxlength-1);

4) 去掉其中的 ‘#’字符,就得到回文串。

 

代码如下:

class Solution {
public:
    string longestPalindrome(string s) {
        //小于1的字符串免处理,直接返回
        if(s.size()<=1){
            return s;
        }
        
        int len = s.size();
        string str = preProcess(s);
        //使用一个变量maxlength记录最长回文子串向左/右扩张的长度,以及一个maxidx记录当前最大回文串的中心位置,判断当前的offset与maxlength的大小,取较大赋值给maxlength。
        int offset,maxidx = 0,maxlength = 0;
        for(int cur = 1; cur < str.size()-1; ++cur){
            //查找最大回文串
            offset = 0;
            while(cur-offset>=1 && cur+offset < str.size() && str[cur-offset] == str[cur+offset]) {
                ++offset;
            }
            
            //更新maxlength
            if(maxlength < offset){
                maxlength = offset;
                maxidx = cur;
            }  
        }
        
        //截取最长回文串
        string longeststr = str.substr(maxidx-maxlength+1,2*maxlength-1);
        //去除"#"字符
        string result = "";
        for(int i = 0; i<longeststr.size();i++){
            if(longeststr[i]!='#')
                result+=longeststr[i];
        }
        return result;
    }
private:
    //预处理
    string preProcess(string s){
        string str = "$";
        int len = s.size();
        for(int i = 0; i<len; i++)
        {
            str+="#";
            str+=s[i];
        }
        str+="#";
        return str;
    }
};

 

posted @ 2018-03-02 19:59  HOU_JUN  阅读(360)  评论(0编辑  收藏  举报