学习自这篇博客, 博主写得非常好, 算法原理请看这篇博客, 而代码实现下面的更明了
int p[100000];
string solve(string s)
{
string t = "$#";
for (int i = 0; i < s.length(); i++)
{
t += s[i];
t += '#';
}
//mx是回文串能延伸到的最右端的位置
//id为能延伸到最右端的位置的那个回文子串的中心点位置
//reslen表最长回文串半径
//rescen为最长回文串中心
int mx = 0, id = 0, reslen = 0, rescen = 0;
for (int i = 1; i < t.length(); i++)
{
p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
while (t[i + p[i]] == t[i - p[i]]) ++p[i];
if (mx < i + p[i])
{
mx = i + p[i];
id = i;
}
if (reslen < p[i])
{
reslen = p[i];
rescen = i;
}
}
//最长子串的长度是半径减1,起始位置是中间位置减去半径再除以2
return s.substr((rescen - reslen)/2, reslen - 1);
}
小A的回文串
链接:https://ac.nowcoder.com/acm/contest/549/B
小A非常喜欢回文串,当然我们都知道回文串这种情况是非常特殊的。所以小A只想知道给定的一个字符串的最大回文子串是多少,但是小A对这个结果并不是非常满意。现在小A可以对这个字符串做一些改动,他可以把这个字符串最前面的某一段连续的字符(不改变顺序)移动到原先字符串的末尾。那么请问小A通过这样的操作之后(也可以选择不移动)能够得到最大回文子串的长度是多少。
#include<iostream>
#include<cmath>
#include<vector>
#include<string>
#include <stdio.h>
#include<algorithm>
#include<functional>
#define rep(a,b) for(int i=a;i<b;i++)
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int p[100000];
int solve(string s)
{
string t = "$#";
for (int i = 0; i < s.size(); ++i) {
t += s[i];
t += "#";
}
int mx = 0, id = 0, reslen = 0;
for (int i = 1; i < t.length(); i++)
{
p[i] = mx > i ? min(p[id * 2 - i], mx - i) : 1;
while (t[i + p[i]] == t[i - p[i]]) ++p[i];
if (mx < i + p[i])
{
mx = i + p[i];
id = i;
}
reslen = max(reslen, p[i]);
}
return reslen - 1;
}
int main()
{
ios::sync_with_stdio(false);
string s;
cin >> s;
int len = s.length();
s += s;
int res = 0;
for (int i = 0; i < s.length() - len; i++)
res = max(res, solve(s.substr(i, len)));
cout << res;
}