Manacher算法求最大回文串
Manacher 算法是用来求最长回文子串的算法
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
int getLongestPalindrome(string A, int n) {
// write code here
string s = "$#";
for (const char& ch : A)
{
s += ch;
s += '#';
}
int len = s.size();
s += '!';
int imax = 0;
int rmax = 0;
vector<int> f(len);
for (int i = 1; i < len; ++i)
{
//初始化
f[i] = (i <= rmax) ? min(rmax - i + 1, f[2 * imax - i]) : 1;
//中心扩展
while (s[i + f[i]] == s[i - f[i]]) ++f[i];
//更新
if (f[i] > rmax - imax + 1)
{
imax = i;
rmax = i + f[i] - 1;
}
}
return f[imax]-1; //最长回文子串长度
}
};void Manacher(string s)
{
//改造原字符串,如:asa变成$#a#s#a#!,assa变成$#a#s#s#a#!
string t = "$#";
for (const char &c : s) {
t += c;
t += '#';
}
int len = t.length();
t += '!';
auto f = vector<int>(len);
//对于第一个$和最后一个!,可以不计算以其为中心的最大回文子串
int iMax = 0; //最大回文子串回文中心
int rMax = 0; //最大回文子串右端点
for (int i = 1; i < len; ++i) //计算以i为中心的最大回文子串
{
// 初始化 f[i]:以i为中心的最大回文子串半径,i点也包括在内
//f[2 * iMax - i] = f[iMax - (i - iMax)] = f[i对位],如果对位的f[i]没有超出最大回文串边界(左边界)则f[i]=f[i对位]成立,如1234321倒数第二位的2的f[i]等于顺数第二位的2的f[i]
//如果对位的f[i]超出了最大回文串边界(左边界),则本位的f[i]是从rMax-i+1开始中心增大的,如31234321倒数第二位的2的f[i]不等于顺数第第三位的2的f[i],而是为rMax-i+1
f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1;
// 中心拓展
while (t[i + f[i]] == t[i - f[i]]) ++f[i];
// 动态维护 iMax 和 rMax
if (f[i] > rMax - iMax + 1) //更新最大回文子串及其右边界
{
iMax = i;
rMax = i + f[i] - 1;
}
// if (i + f[i] - 1 > rMax) //更新最右回文子串及其右边界,但它不一定是最长回文子串,求回文串数可用这个条件
// {
// iMax = i;
// rMax = i + f[i] - 1;
// }
// ans += (f[i] / 2);
}
cout << f[iMax] - 1 << endl; //这是最大回文串长度
// for (int i = iMax - f[iMax] + 1; i <= rMax; ++i) //这里输出最大回文串
// {
// if (t[i] != '#')
// {
// cout << t[i];
// }
// }
}例题:
/*
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:"abc"
输出:3
解释:三个回文子串: "a", "b", "c"
示例 2:
输入:"aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
*/
class Solution {
public:
int countSubstrings(string s) {
int n = s.size();
string t = "$#";
for (const char &c: s) {
t += c;
t += '#';
}
n = t.size();
t += '!';
auto f = vector <int> (n);
int iMax = 0, rMax = 0, ans = 0;
for (int i = 1; i < n; ++i) {
// 初始化 f[i]
f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * iMax - i]) : 1;
// 中心拓展
while (t[i + f[i]] == t[i - f[i]]) ++f[i];
// 动态维护 iMax 和 rMax
if (i + f[i] - 1 > rMax) {
iMax = i;
rMax = i + f[i] - 1;
}
// 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
ans += (f[i] / 2);
}
return ans;
}
};