date: 2024-06-22
title: Manacher Algorithm
status: DONE
dg-publish: true
author:
- AllenYGY
tags:
- Manacher
- String
- NOTE
- Algorithm
created: 2024-06-22T00:52
updated: 2024-06-23T16:15
Manacher Algorithm
给定一个字符串 s
,找到 s
中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成回文覆盖最右边界r、回文中心c
假设一个字符串 s
, 字符串s
的 Manacher扩展串为 p
,p[i]
表示当前字符可以扩展的最长回文串的长度
现在假设我们要对下一个
如果
如果
2*c-i
的回文半径 s[2*c-i]
,在大回文区域以外,直接确定
当前字符最长回文串的实际长度
实际回文串终止位置 = 扩展回文串结尾下标 / 2
string Preprocess(string s) { // 字符串预处理
string res = "#"; //在每个字符前后添加扩展字符
for (int i = 0; i < s.size(); i++) {
res += s[i];
res += "#";
}
return res;
}
string Manacher(string s) {
string t = Preprocess(s);
string ans = "";
vector<int> p(t.size(), 0);
int mx = 0;
for(int i = 0, c = 0, r = 0, len; i < t.size(); i++) {
// 当 i < r 时,
// 若此时 i + s[i] 在 r 内, 则 r - i >= p[2 * c - i]
// len = p[2 * c - i]
// 若此时 i + s[i] 在 r 外, 则 r - i <= p[2 * c - i]
// len = r - i
// 当 i >= r 时
// 回文字符串即为 i 本身,len = 1
len = i < r ? min(r - i, p[2 * c - i]) : 1;
while (i + len < t.size() && i - len >= 0 && t[i + len] == t[i - len]){ // 不管是否可以扩展,都尝试扩展
len++;
}
if (i + len > r){ //更新新的回文中心和回文半径
r = i + len;
c = i;
}
if(len > mx){ // 维护最长回文子字符串
mx = len;
ans = s.substr((i - len + 1)/2, len - 1);
}
p[i] = len;
}
return ans;
}
返回字符串s的回文子串数量
给定一个字符串str和一个正数k
你可以随意把str切分成多个子串
目的是找到某一种划分方案,有尽可能多的回文子串
并且每个回文子串都要求长度>=k、且彼此没有重合的部分
返回最多能划分出几个这样的回文子串
长度前k名的奇数长度回文子串长度乘积
给定一个字符串s和数值k,只关心所有奇数长度的回文子串
返回其中长度前k名的回文子串的长度乘积是多少
如果奇数长度的回文子串个数不够k个,返回-1
最长双回文串长度
输入字符串s,求s的最长双回文子串t的长度
双回文子串就是可以分成两个回文串的字符串
比如"aabb",可以分成"aa"、"bb"