给出一个字符串,我们需要找到最长的回文子字符串,回文子字符串有两种,一种是奇数型,如
aba
,一种是偶数形,如
abba
,所谓的回文字符串就是这个字符串正读或者倒度都是相同的。为了统一处理这两种回文字符串,我们将原字符串每隔一个字符,添加一新字符,我们在这里用
∗
来表示,举个例子就是将
我们将对变换过后的字符串进行扫描。记录以每个元素为中心的最长回文字符串的半径长度。同时我们记录这个回文字符串最右端的位置和maxid进行比较,如果比它大就将它更新,我们用下图来说明这样做的目的
假设当前扫描到第
i
个位置,以它为中心的最长回文字符串的最右端位置为maxid,那么如果下一个扫描到的是位置
这样我们就得到了变换后的字符串的每个元素为中心的最长回文字符串的半径长度。当然包括
∗
,接下来的事情就是读出最长的回文字符串,因为我们在上步中已经记录了最长回文字符串所对应的位置,这样,我们找到这个位置,设为
char *longestPalindrome(char *s)
{
int len_s=strlen(s);
char *new_s=malloc(sizeof(char)*(2*len_s+3));
int *P=malloc(sizeof(int)*(2*len_s+3));
char *result=malloc(sizeof(char)*(len_s+1));
new_s[0]='#';
new_s[2*len_s+2]='$';
int i;
int max_len=0;
int maxid=0;
int id=0,len_id=0;
for(i=1;i<=2*len_s+2;i++)
{
if(i % 2==1)
new_s[i]='*';
else
new_s[i]=s[(i-2)/2];
}
for(i=1;i<2*len_s+2;i++)
{
if(i<maxid)
P[i]=P[2*id-i]>(maxid-i)?(maxid-i):P[2*id-i];
else
P[i]=1;
while(new_s[i-P[i]]==new_s[i+P[i]])
P[i]++;
if(i+P[i]>maxid)
{
maxid=i+P[i];
id=i;
}
if(P[i]>max_len)
{
max_len=P[i];
len_id=i;
}
}
memcpy(result,s+(len_id-max_len)/2,max_len-1);
result[max_len-1]='\0';
return result;
}