原博文地址:http://blog.csdn.net/u012773338/article/details/39857997
最长回文子串
描述:输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串连续出现的字符 串片段。回文的含义是:正着看和倒着看是相同的,如abba和abbebba。在判断是要求忽略所有的标点和空格,且忽略大小写,但输出时按原样输出(首 尾不要输出多余的字符串)。输入字符串长度大于等于1小于等于5000,且单独占一行(如果有多组答案,输出第一组)。
输入 :每行有一个字符串。
输出 :输出所要求的回文子串。
样例输入: Confuciuss say:Madam,I‘m Adam.
样例输出 : Madam,I‘m Adam
思路:
1,用gets或者fgets读入完整的一行,
2,预处理构造一个新的字符串,不包含原来的标点符号,并且把所有字母变成大写。用s数组保存。
3,枚举每个回文串的中间位置i,然后不断向外扩展,直到有字符不同,但是长度为奇数和偶数的处理方式是不一样的,比如aba,abba。
回文串为奇数时,从第i个向左(i-j)向后(i+j)遍历,为偶数时,从第i个向左(i-j)向右(i+j+1)遍历。不想等就退出。
4,不断更新最大回文串长度,并且用一个数组p保存最大回文串在原串的起始位置和结束位置。
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<ctype.h> 4 #define MAXN 5000 + 10 5 char buf[MAXN], s[MAXN]; 6 int p[MAXN]; 7 int main() 8 { 9 int n,m=0,maxn=0,x,y,i,j; 10 fgets(buf,sizeof(s),stdin);//s肯定是一个字符数组。该调用从标准输入流stdin(也就是键盘输入) 11 n=strlen(buf); //读入 s 数组的大小(sizeof(s))再减 1 的长度的字符到 buf 所指的内存空间中(前提是buf已经申请好空间了) 12 for(i=0;i<n;i++) 13 { 14 if(isalpha(buf[i])) //判断字符i是否是字母用到了isalpha这个函数 15 { 16 p[m]=i; //把字母在原串的初始位置保存 17 s[m++]=toupper(buf[i]); //转化成大写字母用s数组保存 18 } 19 } 20 for(i=0;i<m;i++) 21 { 22 for(j=0;i-j>=0&&i+j<m;j++) //枚举奇数的回文串 注意下标的变换 23 { 24 if(s[i-j]!=s[i+j]) break; 25 if(j*2+1>maxn) {maxn=j*2+1;x=p[i-j];y=p[i+j];} //回文串的长度为2*j+1,比如aba,记录起始位置和终止位置 26 } 27 for(j=0;i-j>=0&&i+j+1<m;j++) //枚举偶数的回文串 28 { 29 if(s[i-j]!=s[i+j+1])break; 30 if(j*2+2>maxn) {maxn=j*2+2;x=p[i-j];y=p[i+j+1];} //长度为2*j+2,比如abba, 31 } 32 } 33 for(i=x;i<=y;i++) 34 printf("%c",buf[i]); //输出最长回文串 35 printf("\n"); 36 return 0; 37 }
csu-1328 近似回文词
1328: 近似回文词
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 312 Solved: 118
[Submit][Status][Web
Board]
Description
输入一行文本,输出最长近似回文词连续子串。所谓近似回文词是指满足以下条件的字符串:
1. S以字母开头,字母结尾
2. a(S)和b(S)最多有2k个位置不同,其中a(S)是S删除所有非字母字符并且把所有字母转化成小写之后得到的串,b(S)是a(S)的逆序串。
比如当k=1时,Race cat是一个近似回文词,因为a(S)=racecat和b(S)=tacecar只有2个位置不同。
Input
输入包含不超过25组数据,每组数据包含两行。第一行是整数k(0<=k<=200),第二行为字符串S,包含至少一个字母但不超过1000个字符(换行符不算)。S只包含字符、空格和其他可打印字符(比如逗号,句号),并且不会以空白字符开头。
Output
对于每组测试数据,输出最长近似回文子串的长度和起始位置(S的第一个字符是位置1)。如果有多个最长近似回文子串解,起始位置应尽量小。
Sample Input
1 Wow, it is a Race cat! 0 abcdefg 0 Kitty: Madam, I‘m adam.
Sample Output
Case 1: 8 3 Case 2: 1 1 Case 3: 15 8
HINT
Source
跟上题的区别在于这里可以有2*k个字符不同,那处理的时候只要另外设置一个标志变量ans,当ans>k 就跳出即可,还要注意一些细节的处理,特别是枚举偶数的近似回文串的时候,如果j==0即没有满足题目条件的近似回文串,那么应该不能更新最大值,因为 ab不是回文串,最大长度只能是1。其他的就是一样。
代码:
#include<stdio.h> #include<string.h> #include<ctype.h> #define MAXN 1000 + 10 char buf[MAXN], s[MAXN]; int p[MAXN]; int main() { int k,n,m,maxn,x,y,i,j,l=1,cas,start; while(scanf("%d",&k)!=EOF) { getchar(); fgets(buf,sizeof(s),stdin);//s肯定是一个字符数组。该调用从标准输入流stdin(也就是键盘输入) n=strlen(buf); m=maxn=0; start=-1; //读入 s 数组的大小(sizeof(s))再减 1 的长度的字符到 buf 所指的内存空间中(前提是buf已经申请好空间了) for(i=0;i<n;i++) { if(isalpha(buf[i])) //判断字符i是否是字母用到了isalpha这个函数 { p[m]=i; //把字母在原串的初始位置保存 s[m++]=tolower(buf[i]); //转化成大写字母用s数组保存 } } //s[m]=0; for(i=0;i<m;i++) { for(cas=j=0;i-j>=0&&i+j<m;j++) //枚举奇数的近似回文串 { if(s[i-j]!=s[i+j]) cas++; if(cas>k) break; } j--; if(p[i+j]-p[i-j]+1>maxn) {maxn=p[i+j]-p[i-j]+1; start=p[i-j];} for(cas=j=0;i-j>=0&&i+j+1<m;j++) //枚举偶数的近似回文串 { if(s[i-j]!=s[i+j+1])cas++; if(cas>k) break; } j--; if(j<=-1) continue; if(p[i+j+1]-p[i-j]+1>maxn) {maxn=p[i+j+1]-p[i-j]+1; start=p[i-j];} } printf("Case %d: %d %d\n",l++,maxn,start+1); } return 0; }