链接
题意
给出字符串,求其最长回文子串的长度。
思路
该题目可用manacher算法在O(n)时间内解决。
最长回文子串,也是子串+长度类型的问题,此处使用字符串哈希+二分解决。
对字符串进行正序倒序两次哈希,之后二分长度,对每个长度len枚举子串的哈希值,判断相同位置的子串正逆序哈希值是否相同,相同则代表为回文串。
复杂度O(n*log(n))。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef unsigned long long ulint;
const ulint seed = 30007uLL;
#define maxn 1010000
ulint H[maxn], P[maxn], xp[maxn];
char s[maxn];
int N;
void initHash()
{
H[0] = s[0];
for(int i = 1; i < N; i++)
H[i] = H[i - 1]*seed + s[i];
P[N-1] = s[N-1];
for(int i = N-2; i >= 0; i--)
P[i] = P[i + 1]*seed + s[i];
}
ulint askHash(int l, int r)
{
if(l == 0) return H[r];
return H[r] - H[l - 1]*xp[r - l + 1];
}
ulint askP(int l, int r)
{
if(r == N-1) return P[l];
return P[l] - P[r + 1]*xp[r - l + 1];
}
bool check(int len)
{
//cout << "len = " << len << endl;
ulint ht, pt;
for(int i = 0, l, r; i + len - 1 < N; i++)
{
l = i, r = i + len - 1;
ht = askHash(l, r);
pt = askP(l, r);
//cout << ht << " " << pt << endl;
if(ht == pt) return true;
}
return false;
}
int main()
{
xp[0] = 1;
for(int i = 1; i < maxn; i++)
{
xp[i] = xp[i-1] * seed;
}
int kase = 0;
while(~scanf("%s", &s))
{
if(string(s) == string("END"))
break;
N = strlen(s);
for(int i = 0; i < N; i++)
{
s[i] = s[i] - 'a' + 1;
}
initHash();
/*
for(int i = 0; i < N; i++)
{
cout << askHash(i, i) << " " << askP(i, i) << endl;
}
*/
vector<int> dexod, dexev;
for(int i = 1; i <= N; i++)
{
if(i % 2) dexod.push_back(i);
else dexev.push_back(i);
}
int ans = 0, l = 0, r = dexod.size() - 1, m;
while(l <= r)
{
m = (l + r) >> 1;
if(check(dexod[m]))
{
l = m + 1;
ans = dexod[m];
}
else r = m - 1;
}
l = 0, r = dexev.size() - 1;
while(l <= r)
{
m = (l + r) >> 1;
if(check(dexev[m]))
{
l = m + 1;
ans = max(ans, dexev[m]);
}
else r = m - 1;
}
printf("Case %d: ", ++kase);
cout << ans << endl;
}
return 0;
}