题目描述
给定一个字符串,求它的最长回文子串的长度。
Manacher算法
这是一个经典的算法问题,近期在网上看了很多人的讲解,感觉仍不是特别清晰,起码看起来还是有些累的。终于在看了一个英文介绍(http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html),又苦苦思索1天后,豁然开朗,所以把自己的学习心得记录下来,以方便以后复习。
首先放上C++的程序实现(代码引自http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html,添加了一些注释,将结尾查找起始点的部分删除),代码十分晦涩,如果不需要知道原理只需要实现方法的朋友,请直接粘贴到你的程序中即可运行。如果希望知道原理,请结合后面的分析阅读。
/**********************************************************
* Manacher's algorithm should insert special character(#)
* into original string, then all strings whatever it's
* length is odd or even will be extened to even.
* And add a specila charactor at the begin and end of the
* string to avoid over position limitition. Such as
* "abaca" should be change to "^#a#b#a#c#a#$"
**********************************************************/
string ManacherPreprocess(const string& str)
{
string s = "^";
for(string::size_type i = 0; i < str.length(); ++i)
{
s+="#";
s+=str[i];
}
s+="#$";
return s;
}
/**********************************************************
* find out the longest palindromic substring.
**********************************************************/
string LongestPalindromeManacher(const string& str)
{
string T = ManacherPreprocess(str);
int cIndex = 0; //index of center of Palindromic substring in T. the substring is the nearest and longest
int rightEdge = 0; //right edge index of Palindromic string centers at cIndex.
// store intermediate result in an array P,
// where P[i] equals to the length of the palindrome centers at T[i].
int N = T.length();
int *P = new int[N];
//Length of the longest Palindromic substring
int maxLen = 0;
int centerIndexOfMax = 0;
for(int i = 1; i < N - 1; ++i)
{
//mirrorIndex is the mirrored index of i based on cIndex.
//In fact, this mirrorIndex is only meaningful while i is
//in the index range of Palindromic string which center is cIndex.
//
//If i is out of range, should calculate Palindromic string
//centered in i.
int mirrorIndex = 2 * cIndex - i;
//We assume there's a Palindromic string which centers at cIndex.
P[i] = (rightEdge > i) ? min(rightEdge-i, P[mirrorIndex]) : 0;
//Try to find out the Palindromic string which center is i
while(T[i + 1 + P[i]] == T[i - 1 - P[i]])
P[i]++;
if((i + P[i]) > rightEdge)
{
//Palindromic string centers at cIndex even cannot cover T[i],
//so cannot conver the right parts. so move cIndex to i and update rightEdge.
cIndex = i;
rightEdge = i + P[i];
}
//Record index of which item in P contains the longest Palindromic substring
//and the length of the substring.
//These will be used to find out the real substring from input str.
if(maxLen < P[i])
{
maxLen = P[i];
centerIndexOfMax = i;
}
}
/* Original statements which cost extra O(N), so remove */
/* Find the maximum element in P.
/***********************************************************/
//int maxLen = 0;
//int centerIndexOfMax = 0;
//for (int i = 1; i < N-1; i++)
//{
// if (P[i] > maxLen)
// {
// maxLen = P[i];
// centerIndex = i;
// }
//}
delete []P;
return str.substr((centerIndexOfMax - 1 - maxLen)/2, maxLen);
}