manacher是一种线性时间复杂度算法,对于给定的字符串s, 可以在O(n)时间内,求出以每个位置为中心的最长回文子串。
- 插入无关字符
在相邻字符之间以及字符串首尾分别插入s中没出现的字符,设为#,得到str。则str中以任意位置为中心的最长回文串长度是奇数。 - 记
p[i]=max{j|开区间str(i−j...i+j)是回文串}。
因此只要求出p数组即可。 假设从左向右扫描,当前在i点,定义
id=argmaxj{j+p[j] | j<i}
分两种情况:
1. i < id + p[id], 这时找 i关于id的对称点id*2-i,根据该点p值更新i点;
2. i >= id + p[id], 暴力求解i点p值因为每次比较都是在增加id+p[id]的值,显然id+p[id]上限是字符串长度,因此复杂度O(n)。
class Solution {
public:
string longestPalindrome(string s) {
char st[s.length()*2+5] = {0};
int p[s.length()*2+5] = {0};
int len = 0;
st[len++] = '%';
for (int i = 0; i < s.length(); ++i) {
st[len++] = '#', st[len++] = s[i];
}
st[len++] = '#'; st[len] = '\0';
p[0] = 0;
int ans = 0;
for (int id = 0, i = 1; i < len - 1; ++i) {
int r = id + p[id];
p[i]= r > i ? min(p[id * 2 - i], r - i) : 1;
while(st[i - p[i]] == st[i + p[i]]) ++ p[i];
if (i + p[i] > r) id = i;
if (p[i] > p[ans]) ans = i;
}
return s.substr((ans - p[ans])/2, p[ans]-1);
}
};