最长回文子串

来源:互联网 发布:vue2.0缓存页面数据 编辑:程序博客网 时间:2024/05/18 01:44

输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同。如abba和yyxyy。在判断时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独的一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。

样例输入:Confuciuss say:Madam,I'm Adam.

样例输出:Madam,I'm Adam

【分析】

由于输入的字符比较复杂,首先,不能用scanf("%s")输入字符串,可用下述两种方法解决下列问题:

第1种方法是使用fgetc(fin),它读取一个打开的文件fin,读取一个字符,然后返回一个int值。因为如果文件结束,fgetc将返回一个特殊标记EOF,它并不是一个char。如果要从标准输入读取一个字符,可以用getchar(),它等价于fgetc(stdin)。

提示3-14:使用fgetc(fin)可以打开的文件fin中读取一个字符。一般情况下应当在检查它不是EOF后再将其转换成char值。从标准输入读取一个字符可以用getchar(),它等价于fgetc(stdin)。

fgetc()和getchar()将读取“下一个字符”,如果是空格,会正常读取;若是换行,读取到的将是回车符'\n'。

潜在的陷阱:不同操作系统的回车换行符是不一致的。Windows是'\r'和'\n'两个字符,Linux是'\n',而MacOS是'\r'。如果在Windows下读到Windows文件,fgetc()和getchar()会把'\r'吃掉,只剩下'\n';但如要要在Linux下读取同样一个文件,它们会先读到'\r',然后才是'\n'。这个问题在竞赛时一定要注意。

提示3-15:在使用fgetc和getchar时,应该避免写出和操作系统相关的程序。

第2种方法是使用fgets(buf,MAXN,fin)读了完整的一行,其中buf的声明为char buf[MAXN]。这个函数读取不超过MAXN-1个字符,然后在末尾上结束符'\0',因此不会出现越界的情况。之所以说可以用这个函数读取完整的一行,是因为一旦读到回车符'\n',读取工作将会停止,而这个'\n'也会是buf字符串中最后一个有效字符(再往后就是字符串的结束符'\0'了)。只有一种情况下,buf不会以'\n'结尾:读到文件结束符,并且文件的最后一个不是以'\n'结尾。

提示3-16:fgets(buf,MAXN,fin)将读取完整的一行放在字符数组buf中。你应当保证buf足够存放下文件的一行内容。除了在文件结束符前没有遇到'\n'这种特殊情况外,buf总是以'\n'结尾。当一个字符都没有读到时,fgets返回NULL。

gets(s)表示从标准输入设备读取字符串存入s所指向的数组中,成功时返回指针s,否则返回NULL。但是gets(s)没有指明读到的最大字符数,gets函数也不管s的可用空间有多大。

提示3-17:C语言并不禁止程序读写“非法内存”。例如你声明的是char s[100],你完全可以赋值s[10000]='a'(甚至-Wall也不会警告),但后果自负。

提示3-18:C语言中的gets(s)存在缓冲区溢出漏洞,不推荐使用。

选择fgets函数可以解决“输入有空格”的问题,它可以一次性读取一行,最为方便。

接下来,解决“判断时忽略标点,输出进却要按原样”的问题,可以用一个通用的方案:预处理。构造一个新字符串,不包含原来的标点符号,而且所有字符变成大写(顺便解决了大小写的问题):

n = strlen(buf);

m=0;

for(i = 0; i < n; i++)

   if(isalpha(buf[i]))   s[m++] = toupper(buf[i]);

说明:isalpha(c)的原型包含在ctype.h中,它用于判断字符c是否为字母(大写或小写)。用toupper(c)返回c的大写形式。这样处理之后,buf保存的就是原串的所有字母了。

提示3-19:当任务比较复杂时,可以用预处理的方式简化输入,并提供更多的数据供使用复杂的字符串处理题目往往可以通过合理的预处理简化任务,便于调试。

提示3-20:头文件ctype.h中定义的isalpha、isdigit、isprint等工具可以用来判断字符的属性,而toupper、tolower等工具可以用来转换大小写。

说明:(1)isalpha(c)用来检查c是否为字母,如果是字母,则返回1;否则返回0。

(2)isdigit(c)用来检查c是否为数字(0~9),如果是数字,则返回1;否则返回0。

(3)isprint(c)用来检查c是否为可打印字符(不包括空格),其ASCII码值在0x21~0x7e之间,如果是可打印字符,则返回1;否则返回0。

(4)toupper(c)用来将c字符转换为大写字母,返回c对应的大写字母。

(5)tolower(c)用来将c字符转换为小写字母,返回c对应的小写字母。

 

源码:

#include<iostream>#include<string.h>#include<stdio.h>#include<ctype.h>#include<algorithm>#include<stack>#include<queue>#include<math.h>using namespace std;char a[999];   //输入char big[999];//big记录buf中字母并转换成大写char position[999];//position记录res中字母在buf中位置int i,j;int main(){    int t;    int l,r;    scanf("%d",&t);    getchar();//吸收输入t时的输入残余    while(t--)    {        gets(a);//不能用scanf,因为可能有空格        int w=0;        int len=strlen(a);        for(i=0; i<len; i++)        {            if(isalpha(a[i]))//判断是否是字母            {                big[w]=toupper(a[i]); //字母转换为大写                position[w]=i;     //pri记录res中字母在buf中位置                w++;   //记录有多少个字母            }        }        int max=-1;        for(i=0; i<w; i++)//不预先判断奇偶,先奇后偶,max自动更新        {            for(j=0; i-j>=0&&i-j<w; j++)//最长回文字串为奇数            {                if(big[i-j]!=big[i+j])                    break;//向两边扩展,不相等跳出                if(2*j+1>max)                {                    max=j*2+1;   //记录最长回文字串长度                    l=position[i-j];  //记录最长回文字串起点                    r=position[i+j];  //记录最长回文字串终点                }            }            for(j=0; i-j>=0&&i-j<w; j++) //最长回文字串为偶数            {                if(big[i-j]!=big[i+j+1])//向两边扩展,不相等跳出                    break;                if(2*j+2>max)                {                    max=j*2+2;//记录最长回文字串长度                    l=position[i-j];//记录最长回文字串起点                    r=position[i+j+1];//记录最长回文字串终点                }            }        }        for(i=l; i<=r; i++) //l,r为起点,终点            printf("%c",a[i]);        printf("\n");    }    return 0;}


 

l、r不能起名字为left、right。。。。left&right是函数,,,sad。。。

求最长回文子串长度:

printf("%d\n",max);


 

原创粉丝点击