最长回文
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5319 Accepted Submission(s): 1815
Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa abab
Sample Output
4 3
Source
Recommend
lcy
这个题目我是参考这篇博客写的!
这个扩展的KMP本来就不是怎么好理解,花了半天时间把扩展的KMP搞懂了,想应用一下,没想到想用他求一个最长回文字串都这么困难,表示这个算法不好理解啊
讲的非常详细,思路非常清晰
扩展KMP的优化思路和KMP基本上是一样的就是计算过的不再计算!
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
#define MAX 110010
int next1[MAX];
int next2[MAX];
int next[MAX];
int ans;
char a[MAX];
char b[MAX];
int getNext1(int n)
{
int i=0,j=0,k=0,p=0,a=0,l=0;
next[0]=n;
while(j+1 < n && b[j+1]==b[j]) j++;
next[1]=j;
a=1;
for(i=2;i<n;i++)
{
p=a+next[a]-1;
l=next[i-a];
if(i+l <= p)
next[i]=l;
else
{
j=p-i+1;
if(j<0)
j=0;
while(i+j < n && b[j]==b[i+j]) j++;
next[i]=j;
a=i;
}
}
return 0;
}
void getNext2(char *s, int *nexts, int n, int m)
{
getNext1(m);
int i, j, k;
j = 0;
k = 0;
while (s[j] == b[j])j++;
nexts[0] = j;
for (i = 1; i < n; i++)
{
if (next[i-k] + i < nexts[k] + k)
nexts[i] = next[i-k];
else
{
j = nexts[k] + k - i;
if (j < 0) j = 0;
while (i + j < n && s[i+j] == b[j])j++;
nexts[i] = j;
k = i;
}
}
}
void res(char *s, int n)
{
char st;
int len = (n>>1);
for (int i = 0; i < len; i++)
{
st = s[i];
s[i] = s[n-i-1];
s[n-i-1] = st;
}
}
void find(char *s, int n)
{
if (ans >= n || n < 2)return;
int i, k, x;
int mid;
mid = (n>>1);
for (i = mid; i < n; i++)b[i-mid] = s[i];
b[i-mid] = 0;
res(s, n);
getNext2(s, next1, n, i-mid);
res(s, n);
for (i = 0; i < mid; i++)
b[i] = s[mid-i-1];
b[i] = 0;
getNext2(s, next2, n, mid);
next1[n] = next2[n] = 0;
for (i = 0; i < mid; i++)
{
if (next2[i] >= mid - i)
{
x = mid - i + 2 * next1[n-i];
if (ans < x)ans = x;
}
}
for (i = mid; i < n; i++)
{
if (next1[n-i] >= i - mid)
{
x = i - mid + 2*next2[i];
if (ans < x) ans = x;
}
}
find(s, mid);
find(s+mid, n-mid);
}
int main()
{
int n;
while (scanf("%s", a) != EOF)
{
n = strlen(a);
ans = 1;
find(a, n);
printf("%d\n", ans);
}
return 0;
}