一般求回文子串用的是Manacher算法,但是该算法只是简单判断回文,该题目中需要去除掉空格和标点,所以,自己用了动态规划(加剪枝,取出空号等)。
代码如下:
//最长回文子串 动态规划
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cctype> //for tolower
#define MAXSIZE 5000
char str[MAXSIZE];//="Confuciuss say:Madam,I'm Adam.";
int d[MAXSIZE]; //表示状态,以i为末节点的回文长度
int begin[MAXSIZE]; //以i为末节点的回文序列的起始位置在哪
#define COMP(x) ((str[x]<='z'&&str[x]>='a')||(str[x]<='Z'&&str[x]>='A'))
void printstr() //输入字符串
{
int i=0;
char sh;
printf("请输入样例:");
scanf("%c",&sh);
while(sh!='\n')
{
str[i++]=sh;
scanf("%c",&sh);
}
str[i]=0;
}
int main()
{
freopen("a.txt","r",stdin);
printstr();
int len=strlen(str);
int i,j,k,num=1,flag=0;
d[0]=COMP(0)?1:-1;
begin[0]=d[0]?0:-1;
for(i=1;i<len;i++)
{
if(!COMP(i))
{
d[i]=-1;
begin[i]=-1;
continue;
}
//给一个默认的初始化
d[i]=1;
begin[i]=i;
j=i-1;
while(d[j]==-1&&j>=0)
j--; //循环之后,确定j指定的位置一定是字母或者为-1
if(j<0)
continue;
if(d[j]==1)
{
//case1: a a
if(tolower(str[j])==tolower(str[i]))
{
d[i]=d[j]+1;
begin[i]=j;
}
// case2: ac a
else if(j-1>=0)
{
k=j-1;
while(d[k]==-1&&k>=0)
k--;
if(k>=0&&tolower(str[k])==tolower(str[i]))
{
d[i]=d[j]+2;
begin[i]=k;
}
}
}
else
{
//case3: sssss s
char same=tolower(str[begin[j]]);
for(k=begin[j]+1;k<=j;k++)
{
if(COMP(k))
{
if(tolower(str[k])!=same)
break;
}
}
if(k==j+1&&tolower(str[i])==same)
{
d[i]=d[j]+1;
begin[i]=begin[j];
}
//case4: sdad s
else
{
int temp=begin[j]-1;
while(d[temp]==-1&&temp>=0)
temp--;
if(temp<0) ;
else if(tolower(str[temp])==tolower(str[i]))
{
d[i]=d[j]+2;
begin[i]=temp;
}
}
}
if(d[i]>num)
{
num=d[i];
flag=begin[i];
}
else if(d[i]==num&&begin[i]<flag)
flag=begin[i];
}
printf("请输出样例:");
for(i=flag,k=1;k<=num;i++)
{
if(COMP(i))
k++;
printf("%c",str[i]);
}
//printf("%d\n",num);
return 0;
}