AcWing 139. 回文子串的最大长度
原题链接
中等
作者:
长空孤月
,
2020-06-04 22:45:02
,
所有人可见
,
阅读 592
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
string s;
int cnt = 0;
/*
manacher算法,思想与KMP很像,kmp在子串匹配的过程中,利用子串已有的信息,加快子串的滑动,减少不必要的计算。
而manacher在对以每个i为中心的回文串遍历时,利用前面已经求出的回文串来减少计算。每个中心i可以看作我们计算的小单元。
而它们之间有个很重要的特性就是对称。
举例说明:
在一个以mid为中心r[mid]为半径大回文串中,要求以右边某个点j为中心的回文串,可以利用关于mid对称点i,
根据i的回文串大小r[i],可以推测j的回文大小。
当j不在mid的回文串中时,直接用朴素的中心扩散就行。
当j在mid的回文串中时,需要分情况讨论:
1. 第一个显然的情况是:i的回文串依然在mid回文串的范围内,即 i - r[i] > mid - r[mid]。这时j的回文串半径一定等于r[i]。
为了方便计算,保存右边界位置R,再利用对称性,得到条件 r[i] < R - j
2. 当i的回文左边界刚好与mid左边界相等时,不能确定j的大小,但可以保证r[j] >= r[i]。
3. 当i的回文左边界超出了mid左边界时, r[j]一定等于 R - j 。因为当r[j] > R - j 时,说明j的回文右边界超出了mid右边界,
而j和i是对称的,此时mid的边界是一定能跟着j的扩大而扩大的,而mid在j前面,已经用中心扩散求过了,所以j的右边界已不能扩散。
综上,r[j] 可以取min( r[i], R - j ),再用中心扩散试探能否扩张。
最后再维护R和mid,使得当前mid的R最远。
*/
int main(){
while(cin >> s , s != "END"){
int n = s.size();
cnt ++;
string str = "#";
for (int i = 0 ; i < n; i ++){
str += s[i];
str += "#";
}
n = 2 * n + 1;
int r[n]; // 作用同kmp的next数组,保存已知回文串信息
for (int i = 0; i < n; i++ ) r[i] = 0;
int R = 0, mid = 0;
int max_len = 1;
for (int i = 0; i < n; i ++ ){
if (i < R) {
int symmetry_i = 2 * mid - i; // i在回文串内时利用前面已求得对称性来快速确定基准回文长度。
r[i] = min(R - i, r[symmetry_i]);
}
// 尝试扩大r[i] ,中心扩散
int left = i - (r[i] + 1), right = i + (r[i] + 1);
while ( left >= 0 && right < n && str[left] == str[right]){
r[i] ++ ;
left -- ;
right ++;
}
if (i + r[i] > R ) R = i + r[i], mid = i; // 维护使得当前R最远
if (r[i] > max_len){
max_len = r[i];
}
}
cout <<"Case " << cnt << ": " << max_len << endl;
}
}
/*
动态规划方法:
f(i, j)表示从i到j的子串是否是回文子串。
int dp_sol(string s){
int n = s.size(), max_len = 1, start = 0;
if(n <= 1) return s;
bool f[n+5][n+5];
memset(f, 0, sizeof f);
for (int i = 0; i < n; ++ i) f[i][i] = true;
// 枚举所有区间
int cnt = 0;
for (int j = 0; j < n; ++ j)
for (int i = 0; i < j; ++ i){
if(s[i] == s[j]){
if(j - i < 2) f[i][j] = true;
else f[i][j] = f[i+1][j-1];
}
else
f[i][j] = false;
if(f[i][j]){
if (max_len < j - i + 1){
max_len = j - i + 1;
}
}
}
return max_len;
}
*/