注意是回文子串
1.暴力法
2.中心拓展法
3.动态规划法
4.manacher法
题目(2016腾讯实习生校招笔试题):输入一个字符串,求出其中最长的回文子串(子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同,如abba和abcba),在判断时,应该忽略所有标点符号和空格,且忽略大小写,但输出应该保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。 样例输入:Confuciuss say:Madam,I'm Adam. 样例输出:Madam,I'm Adam 分析:首先,我们不能用scanf("%s")读入样例输入的字符串,因为它碰到空白字符就会停下来。这里我们使用fgets(buf,MAXN,stdin)来读取样例输入。接下来,我们要解决”判断时忽略标点,输出时却要按原样“。这里使用一个通用的方案:预处理。构造一个新的字符串,不包含原来的标点符号,而且所有字符变成大写(顺便解决了大小写问题),用ctype.h中的isalpha(c)判断c是否为大写字母或小写字母,用toupper(c)返回c的大写形式。最后,就只剩下唯一的问题”原样输出“了。我们必须增加一个数组用来保存预处理后的字符在原字符串中的位置。 源码:
#include<stdio.h> #include<string.h> #include<ctype.h> // 用到isalpha、touuper等工具 #define MAXN 5000 + 10 char buf[MAXN], tmp[MAXN]; // buf用来存放样例输入,tmp用来存放经过预处理的输入 int p[MAXN]; // p用来保存经过预处理后字符串tmp中的字符在原字符串buf中的位置 int main() { int n, m = 0, max_len = 0, x, y; int i, j; fgets(buf, MAXN, stdin); // 从标准输入流中读取最多MAXN个字符并且把他们转储到buf中,按回车停止读取 n = strlen(buf); // n为buf中的字符数 for (i = 0; i < n; i++) // 预处理操作 { if (isalpha(buf[i])) // 从buf中取出大小写字母 { tmp[m] = toupper(buf[i]); // 全部转换成大写字母存入tmp中 p[m++] = i; // 保存tmp[m]在buf中的位置i } } for (i = 0; i < m; i++) // 以i为中心向两边扩展 { for (j = 0; i - j >= 0 && i + j < m; j++) // 长度为奇数的回文子串(形如abcba) { if (tmp[i - j] != tmp[i + j]) // 如果已不对称相等,跳出循环 break; if (j * 2 + 1 > max_len) // 因为回文子串的长度为奇数,所以子串的长度应该等于(i+j)-(i-j)+1=j*2+1 { max_len = j * 2 + 1; // 保存当前最长回文子串长度 x = p[i - j]; // 记录子串在buf中的范围x~y y = p[i + j]; } } for (j = 0; i - j >= 0 && i + 1 + j < m; j++)// 长度为偶数的回文子串(形如abba),中心点(两个b)位置分别为i,i+1,向两边扩展范围(i-j,i+1+j) { if (tmp[i - j] != tmp[i + 1 + j]) break; if (j * 2 + 2 > max_len) // 回文子串长度为(i+1+j)-(i-j)+1=j*2+2 { max_len = j * 2 + 2; x = p[i - j]; y = p[i + 1 + j]; } } } for (i = x; i <= y; i++) printf("%c", buf[i]); // 在原字符串buf中定位最长回文子串并输出 printf(" "); return 0; }