manacher算法 (模板)
介绍
计算字符串每个位置的最长回文串,也可以说是计算所有的回文区间。
原理
感觉算法思想和扩展kmp求extend数组十分类似。
先在第一个位置插入'$'以避免小于0的讨论,再在每一个字符之间都插入'#',为了避免对区间奇偶长度的讨论。
用len[i]代表位置i的最长回文右半区间的长度。由于经过上面的处理,这里右半区间的长度就是原字符串的回文区间总长。
设p代表计算过程中,到达的最右边界。a代表对应p的位置。i对a对称的位置为2 * a - i。如果i + len[2 * a - i]没有超过p的范围那么len[i] = len[2 * a - i]。否则就延长并更新p和a。
这里 len[i]-1 就是以位置i中心的回文总长。这里的i包括间隙的位置,从1开始编号。
string s;
char ss[N]; //ss为原串
int len[2 * N]; //结果
void mana() {
s.clear();
s.push_back('$');
s.push_back('#');
for(int i = 0; ss[i]; i++) {
s.push_back(ss[i]);
s.push_back('#');
}
int a = 1, p = 1;
for(int i = 1; i < s.size(); i++) {
if(i < p && len[2 * a - i] < p - i) len[i] = len[2 * a - i];
else {
int l = p - i;
while(i + l < s.size() && s[i + l] == s[i - l]) l++;
len[i] = l;
a = i;
p = i + l;
}
}
}