题目链接
题目描述
给定一个仅由小写字母组成的字符串 ,长度为
。请计算
的最长回文子串的长度。
解题思路
- 马拉车(Manacher)算法:在线性时间
求最长回文子串。
- 预处理:将原串插入分隔符,形如:
再在两端加上哨兵(如
^
与$
),统一奇偶长度回文的处理。设新串长度为。
- 核心变量:
:当前已知回文最长右边界对应的中心;
:该回文的最右端位置;
:以位置
为中心的“回文半径”(包含分隔符的半径)。
- 线性扩展:对每个
,若
,可先取
作为初值,再向两侧继续匹配扩展。若超出,则更新
。
- 答案换算:最终结果为
(减去分隔符的影响)。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s; if (!(cin >> s)) return 0;
// 预处理:^#s0#s1#...#sn#$
string t; t.reserve(s.size() * 2 + 3);
t.push_back('^');
t.push_back('#');
for (char c : s) { t.push_back(c); t.push_back('#'); }
t.push_back('$');
int m = (int)t.size();
vector<int> P(m, 0);
int center = 0, right = 0;
for (int i = 1; i < m - 1; ++i) {
int mirror = 2 * center - i;
if (i < right) P[i] = min(P[mirror], right - i);
while (t[i + 1 + P[i]] == t[i - 1 - P[i]]) ++P[i];
if (i + P[i] > right) { center = i; right = i + P[i]; }
}
int ans = 0;
for (int i = 1; i < m - 1; ++i) ans = max(ans, P[i] - 1);
cout << ans + 1 << '\n';
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
StringBuilder t = new StringBuilder();
t.append('^').append('#');
for (int i = 0; i < s.length(); i++) { t.append(s.charAt(i)).append('#'); }
t.append('$');
int m = t.length();
int[] P = new int[m];
int center = 0, right = 0;
for (int i = 1; i < m - 1; i++) {
int mirror = 2 * center - i;
if (i < right) P[i] = Math.min(P[mirror], right - i);
while (t.charAt(i + 1 + P[i]) == t.charAt(i - 1 - P[i])) P[i]++;
if (i + P[i] > right) { center = i; right = i + P[i]; }
}
int ans = 0;
for (int i = 1; i < m - 1; i++) ans = Math.max(ans, P[i] - 1);
System.out.println(ans + 1);
}
}
s = input().strip()
# 预处理:^#s0#s1#...#sn#$
t = ['^', '#']
for ch in s:
t.append(ch)
t.append('#')
t.append('$')
m = len(t)
P = [0] * m
center = 0
right = 0
for i in range(1, m - 1):
mirror = 2 * center - i
if i < right:
P[i] = min(P[mirror], right - i)
while t[i + 1 + P[i]] == t[i - 1 - P[i]]:
P[i] += 1
if i + P[i] > right:
center = i
right = i + P[i]
ans = 0
for i in range(1, m - 1):
if P[i] - 1 > ans:
ans = P[i] - 1
print(ans + 1)
算法及复杂度
- 算法:马拉车算法;分隔符与哨兵统一奇偶长度回文,中心扩展并维护最右覆盖。
- 时间复杂度:
。
- 空间复杂度:
。