最长回文子串
来源:互联网 发布:2016年nba总决赛g4数据 编辑:程序博客网 时间:2024/06/16 09:54
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正看着和倒看着相同,如abba和yyxyy。在判断时,应该忽略所有标点符号和空格且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符长度不超过5000且占据单独的一行。应该输出最长回文串,如果有多个,输出起始位置最靠左的。
样例输入:Confuciuss say:Madam,I’m Adam.
样例输出:Madam,I’m Adam
本题算法思想:
如果输入的全部都是大写字母,问题就简单了:直接判断每个子串即可。可其他字符的出现把问题弄得复杂了。首先我们不能用scanf(“%s”)输入字符串,因为它碰到空格或者TAB就会停下来。
这里我们使用fgets来解决问题。
其中buf声明为char buf[MAXN]。fgets函数读取不超过MAXN-1个字符,然后在末尾添上结束符‘\0’,因此不会出现越界的情况。之所以说可以用这个函数读取完整的一行,是因为一旦读到回车符‘\n’,读取工作将会停止,而这个‘\n’也会是buf字符串中最后一个有效字符(再往后就是字符串结束符‘\0’了)。只有在一种情况下,buf不会以‘\n’结尾:读到文件结束符,并且文件的最后一个不是以‘\n’结尾。fin是指文件fin,即fgets是从打开的文件fin中读取的。
代码1:从前往后遍历字符串找出回文串。尚未完成版!还应增加一个数组p,用p[i]保存s[i]在buf中的位置—为了原样输出。它可以很容易的在预处理中得到,然后在更新max的同时把p[i]和p[j]保存到x和y,最后输出buf[x]到buf[y]中的所有字符。不过这样程序效率有些低,因此考虑写出代码2中的方法。
#include<iostream>#include<stdio.h>#include<stdlib.h>#include<math.h>#include<algorithm>#include<string.h>#include<ctype.h> //用到isalpha、touuper等工具 using namespace std;#define MAXN 5000+10 char buf[MAXN],s[MAXN];int main() { int n,m=0,max=0; int i,j,k; fgets(buf,sizeof(s),stdin); //从标准输入流中读取sizeof(s)-1个字符并且把他们转储到buf中 n=strlen(buf); //获取buf的长度,包含文件结束符'\0' for(i=0;i<n;i++) //构造一个新的字符串,把标点符号过滤掉,随便把小写字母变为大写 if(isalpha(buf[i])) s[m++]=toupper(buf[i]); for(i=0;i<m;i++) //枚举回文串的起点和终点,然后判断它是否真的是回文串;其中m是新字符串s的长度 for(j=i;j<m;j++) { int ok=1; for(k=i;k<=j;k++) //判断s[i..j]是否为回文串;注意这里的循环变量不能是i或j,因为它们已经在外层用过了。s[k]的"对称"位置是s[i+j-k] ! if(s[k]!=s[i+j-k]) ok=0; //只要一次比较失败,就应把标记ok置为0 if(ok && j-i+1>max) max=j-i+1; //max保存当前发现的最长回文串的长度,j-i+1是当前回文串的长度 } printf("max=%d\n",max); return 0; }
代码2:从中间往两边遍历字符串找出回文串;即枚举回文串的“中间”位置i,然后不断往外扩展,直到有字符不同。 注意:长度为奇数和偶数的处理方式是不一样的。 (代码2是完整的)
#include<iostream>#include<stdio.h>#include<stdlib.h>#include<math.h>#include<algorithm>#include<string.h>#include<ctype.h> //用到isalpha、touuper等工具 using namespace std;#define MAXN 5000+10 char buf[MAXN],s[MAXN];int p[MAXN]; //增设数组p,用于保存s[i]在buf中的位置 int main() { int n,m=0,max=0,x,y; int i,j,k; fgets(buf,sizeof(s),stdin); //从标准输入流中读取sizeof(s)-1个字符并且把他们转储到buf中 n=strlen(buf); //获取buf的长度,包含文件结束符'\0' for(i=0;i<n;i++) if(isalpha(buf[i])) //构造一个新的字符串,把标点符号过滤掉,随便把小写字母变为大写 { p[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的关系:i-j>=0表示i到j的距离不能上溢 //i+j<m表示i再加j个位置没有超过字符串s的总长 { if(s[i-j]!=s[i+j]) break; //如果以i为中间点,左边i-j个点字符跟右边i+j个点不同,跳出循环 if(j*2+1>max) //因为子串的长度为奇数,所以子串的长度应该等于j*2+1(j为以i为中心,往两边的距离) { max=j*2+1; x=p[i-j];y=p[i+j]; } //保存当前最长回文子串长度,记录子串范围 } for(j=0;i-j>=0 && i+j+1<m; j++)//这个for循环遍历的子串长度为偶数, //中间点i取子串长度的中点,导致两边长度不均,右边的距离应该再加1 { if(s[i-j]!=s[i+j+1]) break; if(j*2+2>max) { max=j*2+2; x=p[i-j]; y=p[i+j+1]; } } } for(i=x;i<=y;i++) //把最长回文子串输出 printf("%c",buf[i]); printf("\n"); return 0; }
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- 最长回文子串
- javase-函数(方法)
- 渲染管线
- listView分类型,getItemViewType()的用法
- 2017年微信小程序历程
- 限制input输入框的内容
- 最长回文子串
- vistual studio 2013的激活密钥
- 让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法
- 323
- maven一
- HTML实体符号代码速查表
- 练习1-1
- 什么是渲染目标(render target)&& 渲染到纹理(Render To Texture, RTT)详解
- KMP算法