Manacher算法

给定一个子符串S,找出最长回文子串。


用中心扩展法求最长回文子串,可以达到O(N2)的时间复杂度。而Manacher算法可以进一步达到O(n)。

算法特点:

1. 将偶数和奇数长度回文字符串都转化成奇数长度回文字符串统一处理。这是通过在每相邻字符之间插入分隔字符达到的。

如:S = “abaaba”, T = “#a#b#a#a#b#a#”

2. 以每个字符为中心,向外扩展回文。方法同中心扩展法一样。但Manacher算法引入一个辅助数组,来避免重复劳动。

引入辅助数组P,P[i]表示以字符T[i]为中心的回文串的长度(半径)。

请看以下示意图

当开始扩展以T[i]为中心的回文字符串时,就可以利用辅助数P避免重复劳动。

           if (mx > i)
              P[i] = min(P[j],mx-i); // 利用已有成果避免重复劳动
           else
              P[i] = 0;

           while (T[i+P[i]+1] == T[i-P[i]-1])
              P[i]++;  // 以i为中心向两边扩张



    string longestPalindrome(string s) {
       string T;
       T.reserve(s.length()*2+3);
       if (s.length() == 0)
          T = "^&";
       else
       {
          T = "^#";
          for (int i=0;i<s.length();i++)
          {
            T += s[i];
            T += '#';
          }
          T += "&";
       }

       int *P = new int[T.length()];
       int id = 0;
       int mx = 0;
       for (int i=0; i<T.length(); i++)
       {
           if (mx > i)
              P[i] = min(P[id*2-i],mx-i);
           else
              P[i] = 0;

           while (T[i+P[i]+1] == T[i-P[i]-1])
              P[i]++;

           if (P[i]+i > mx)
           {
              mx = P[i];
              id = i;
           }
       }

       mx = 0;
       id = 0;
       for (int i=0; i<T.length(); i++)
       {
          if (P[i] > mx)
          {
             mx = P[i];
             id = i;
          }
       }

       delete[] P;
       
       return s.substr((id-mx+1)/2-1,mx);
    }

算法首先将字符串S转化成T。

例如:S = "abba", T = "^#a#b#b#a#$".

^和$是哨兵自符,可以避免越界条件检查。


在求出转化后字符串T的最长回文子串后,如何取掉那些添加的分隔符呢?

答案是不用去除,直接从源串S中取相应的子串就可以。

这就涉及到一个下标映射的问题。

设S串的下标i,对应字符S[i]在T串的位置为j = i * 2 + 2 (算上^)

则 i = j/2-1

在T中,最大回文子串为[id-mx, id+mx]

引用上面公式,在S中,则对应子串为[(id-mx)/2-1, (id+mx)/2-1]

考虑到回文子串最前最后必为添加的分隔符,故需对上面作一个裁剪修正。

[(id-mx+1)/2-1, (id+mx-1)/2-1]


这就是为什么在函数最后返回

s.substr((id-mx+1)/2-1,mx);
的一个简单推导。


参考资料:

http://blog.csdn.net/ggggiqnypgjg/article/details/6645824

http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值