学习自《算法竞赛入门经典》
/*
* 输入一个字符串,求出其中最长的回文子串。
*子串的含义是:在原串中连续出现的字符串片段。 在判断时,应该忽略所有标点符号和空格
*且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。
*输入字符长度不超过5000, 且占据单独的一行。
*应该输出最长回文串,如果有多个,输出起始位置最靠左的。
*样例输入:Confuciuss say:Madam,I'm Adam.
*样例输出:Madam,I'm Adam
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h> //用到isalpha、touuper等工具
#define MAXN 5010
char buf[MAXN],s[MAXN]; //分别是原数组,经过预处理以后的数组
int pos[MAXN]; //用于保存s[i]在buf中的位置
int main()
{
int n,m=0,max=0,x,y;
int i,j,k;
fgets(buf,sizeof(buf),stdin);//从标准输入流中读取一整行的内容放在buf中(包括换行符)
n= strlen(buf);
for(i=0;i<n;i++)
{
if(isalpha(buf[i])) //构造一个新的字符串,把标点符号过滤掉,随便把小写字母变为大写
{
pos[m]=i; //保存s[m]在buf的位置
s[m++]=toupper(buf[i]);
}
}
for(i=0;i<m;i++) //遍历字符串s,以i为"中间"位置,然后根据j的值不断向两边扩展
{
//这个for循环遍历的子串长度为奇数
for(j=0;i-j>=0 && i+j<m;j++) //i-j>=0表示i到j的距离不能上溢
//i+j<m表示i再加j个位置没有超过字符串s的总长
{
if(s[i-j]!=s[i+j]) break; //如果左右对应位置不匹配
if(j*2+1>max)
{
max=j*2+1; //更新max
x=pos[i-j]; //记录子串范围
y=pos[i+j];
}
}
//这个for循环遍历的子串长度为偶数
for(j=0;i-j>=0 && i+j<m;j++)
{
//中间点i取子串长度的中点,导致两边长度不均,右边的距离应该再加1
if(s[i-j]!=s[i+j+1]) break;
if(j*2+2>max)
{
max=j*2+2;
x=pos[i-j];
y=pos[i+j+1];
}
}
}
for(i=x;i<=y;i++) //把最长回文子串输出
printf("%c",buf[i]);
return 0;
}