Manacher算法--O(N)回文子串算法

具体参考:http://articles.leetcode.com/longest-palindromic-substring-part-ii

这是个利用枚举中心节点以及能到达的最右边界来跳过一些无谓的比较的算法。

核心思想就是:

假设我们用C表示当前回文串的中心位置,P[i]记录当前的最大半径,R表示当前回文串向右能到的最远的位置,也就是说R=C+P[C],i'表示i关于C的对称点。由于构造P数组的时候是从左往右的,所以P[i]是可以利用P[i']记录的信息来对当前位置进行扩展,而这也是这个算法的关键所在。

if P[ i’ ] ≤ R – i,
then P[ i ] ← P[ i’ ]
else P[ i ] ≥ P[ i’ ]. (Which we have to expand past the right edge (R) to find P[ i ].

知道怎么求P[i]之后,还要知道什么时候挪动中心点。当i+P[i]>R的时候就可以将i做新的中心点了。

完整代码如下:

// Transform S into T.
// For example, S = "abba", T = "^#a#b#b#a#$".
// ^ and $ signs are sentinels appended to each end to avoid bounds checking
string preProcess(string s) {
  int n = s.length();
  if (n == 0) return "^$";
  string ret = "^";
  for (int i = 0; i < n; i++)
    ret += "#" + s.substr(i, 1);

  ret += "#$";
  return ret;
}

string longestPalindrome(string s) {
  string T = preProcess(s);
  int n = T.length();
  int *P = new int[n];
  int C = 0, R = 0;
  for (int i = 1; i < n-1; i++) {
    int i_mirror = 2*C-i; // equals to i' = C - (i-C)
    
    P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;
    
    // Attempt to expand palindrome centered at i
    while (T[i + 1 + P[i]] == T[i - 1 - P[i]])
      P[i]++;

    // If palindrome centered at i expand past R,
    // adjust center based on expanded palindrome.
    if (i + P[i] > R) {
      C = i;
      R = i + P[i];
    }
  }

  // Find the maximum element in P.
  int maxLen = 0;
  int centerIndex = 0;
  for (int i = 1; i < n-1; i++) {
    if (P[i] > maxLen) {
      maxLen = P[i];
      centerIndex = i;
    }
  }
  delete[] P;
  
  return s.substr((centerIndex - 1 - maxLen)/2, maxLen);
}

 

posted @ 2017-02-28 16:14  Tsunami_lj  阅读(186)  评论(0编辑  收藏  举报