跟之前算法没什么区别的地方就是,还是需要两两对比确定是否为Palidrome
maintain一个叫lens的array,lens[i] - 以i为中心的最大Palindrome的半径(包括自身)
example:s="OABAXABAO" -> lens[2] = 2, 以"B"为中心的最大Palindrome半径为2
计算方法为
lens[i] = 1
for(s[i+lens[i]] == s[i-lens[i]]){
lens[i]++;
}
区别于之前两种算法,Manacher's Algorithm将palindrome的symmetric特性用到了极致
1.基本运用 我们还是看这条string s="OABAXABAO",已知s是palindrome,左边B跟右边B关于X对称
更加神奇的是源于palidrome's symmetricity,lens[6] = lens[2] = 2 [右边B跟左边B最大Palindrome半径也相等]
2.左越界 But this is not always the case,比如说 s="XABAXABAO",lens[2] = 3,lens[6] = 2 [左边B最大Palindrome半径为3,右边B最大Palindrome半径为2] 尽管两个B还是关于X对称,但是左边B最大Palindrome半径已经超过了X 最大Palindrome的管辖范围,所以右边B最大Palindrome半径不能单纯的利用对称,应该至少是lens[6] = 4 - 2 [右边B最大Palindrome半径为 index of X 减去index of 左边B]
3.右越界 这还没完,比如说 s="OABAXABAX",lens[2] = 2,lens[6] = 3 [左边B最大Palindrome半径为2,右边B最大Palindrome半径为3] 同上,右边B最大Palindrome半径不能单纯的利用对称,应该至少是左边B最大Palindrome半径的大小。
稍稍总结一下,运用palindrome的对称性:
如果左右都不越界,右B最大Palindrome半径就是左B最大Palindrome半径
如果左越界,右B最大Palindrome半径就是至少是左B跟中心X的距离
如果右越界,右B最大Palindrome半径就是至少是左B最大Palindrome半径
[哈哈,但真实的世界总是给你一记耳光~] 其实遍历array的时候,根本就不能提前知道是否右越界,所以最后右B最大Palindrome半径应该至少是 min(lens[左B], 左B跟中心X的距离)
聪明的小伙伴可能发现了,你上面说的palidrome's symmetricity全都是奇数Palindrome啊?那偶数的怎么办啊?
来,不急~ 使用Manacher's Algorithm还需要预处理,在每个字母两边都要插入“#”,比如
"OABAXABAO" -> "#O#A#B#A#X#A#B#A#O#"
那就全变成奇数Palindrome了啊~~~ 开心?
接下来,解释code啦~
i - current index
mx - 之前出现Palindrome里右边到达的最远index (用于判断i是否在某个Palindrome里)
id - 之前出现右边到达的最远Palindrome的中心(用于得到i的对称点)
lens[i] = mx > i ? min(lens[2*id-1], mx-i) : 1;
mx > i:i是否在某个Palindrome里?
是:min(lens[2*id-1], mx-i),至少为min(对称点的最大Palindrome半径, 对称点到中心的距离)
否:1
然后用最开始提到的方法计算最终的最大Palindrome半径,update各种variables
class Solution {
public:
string longestPalindrome(string s) {
if(s.empty()) return "";
string t = "$#";
for(char c: s){
t += c;
t += '#';
}
vector<int> lens(t.size(), 0);
int mx=0, id=0, resLen=0, resCenter=0;
for(int i=1;i<t.size();i++){
lens[i] = mx > i ? min(lens[2*id-i], mx-i):1;
while(t[i+lens[i]]==t[i-lens[i]]) lens[i]++;
if(mx<i+lens[i]){
mx = i+lens[i];
id = i;
}
if(resLen<lens[i]){
resLen = lens[i];
resCenter = i;
}
}
return s.substr((resCenter - resLen) / 2, resLen - 1);
}
};
Reference:
http://www.cnblogs.com/grandyang/p/4475985.html
https://blog.crimx.com/2017/07/06/manachers-algorithm/