manacher算法用于
字符串预处理:aba 处理成 #a#b#a#,方便处理偶回文和奇回文,代码如下
string manacherString(string original_str){
string res(original_str.size() * 2 + 1, ' ');
int index = 0;
for (int i = 0; i < res.size(); i++) {
res[i] = (i & 1) == 0 ? '#': original_str[index++];//(i & 1) == 0代表i是偶数
}
return res;
}
概念:
回文半径:#a#b#a#字符串一共七个字符, 回文半径分别为1, 2,1, 4,1, 2, 1
回文半径数组:#a#b#a#的回文半径数组就是[1, 2,1, 4,1, 2, 1],回文半径数组的最大值减一就是最长回文子串长度,无论是回文半径最大值发生在实轴还是虚轴上。
回文右边界:#a#b#a#字符串中,以第一个字符a为回文中心的回文右边界就是字符b
回文数组的求取:设待求取位置为i, 右边界为R,回文中心为 C , i关于回文中心C对称的位置为i'
讨论分为两大情况,4种小情况
一.i不在右边界里,暴力向两边扩展,无法优化
二.i在右边界里
1.i'的回文半径在边界里, i处半径与i'处半径相同
2.i'的回文半径超过了边界,i处从边界处开始扩展
3.i'的回文边界与边界重合,i处也是冲边界处开始扩展
情况如下图:
初始值:右边界和回文中心都为-1
int maxPalindromeString(string str) {
if (str.size() == 0) {
return 0;
}
str = manacherString(str);
cout << str << endl;
vector<int> pArr(str.size());
int center = -1;
int right = -1;
int maxLen = INT_MIN;
for (int i = 0; i < str.size(); i++)
{
pArr[i] = right > i ? min(pArr[2 * center - i], right - i) : 1;//几种情况都扩展处理
while (i + pArr[i] < str.size() && i - pArr[i] > -1) {
if (str[i + pArr[i]] == str[i - pArr[i]]){
pArr[i]++;
}
else {
break;
}
}
if (i + pArr[i] > right)
{
right = i + pArr[i];
center = i;
}
maxLen = max(maxLen, pArr[i]);
}
return maxLen - 1;
}