题目1 : 最长回文子串
时间限制: 1000ms
描述
小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。
这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”
小Ho奇怪的问道:“什么叫做最长回文子串呢?”
小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”
小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?
小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”
3 abababa aaaabaa acacdas样例输出
7 5 3
题目分析:
求最长回文子串,我们从字符串第一个字符开始,以他为中心,向两边扩散,比较两边字符是否相等,相等则记录下来,继续向两边扩展;不相等,记下当前长度,更换中心字符,依次类推,直到遍历完整个字符串,输出当前值,即为最长回文子串的长度。
这里我调试的时候发现一个问题,即c++中数组下标可以是负值。这样的话有些细节就需要注意。calcul()函数中的下面这几行
while(p[s-1] == p[e+1] && s > 0)
{
s--;
e++;
}
中的 s>0 必须要加,读者可以试试把这个约束条件去掉,第一个示例会出现什么样的结果。如果不加,则会出现一个比示例长度还大的最大回文子串。这是怎么回事呢,经过调试我们可以很明显的看到,指示下标 s 多次指向负下标的数组值,导致使回文子串变大。代码实现:
#include <iostream>
#include <cstdio>
using namespace std;
int n; //用例个数
char str[100000]; //定义一个字符数组
int calcul(char *p)
{
int ans = 1; //初始化个数,至少为一个
for(int i = 0; p[i]; i++) //构建循环
{
int s = i;
int e = i;
int t;
while(p[i] == p[e+1]) //以第 i 个字符为中心,向两侧伸展,统计个数
e++;
i = e;
while(p[s-1] == p[e+1] && s > 0)
{
s--;
e++;
}
if((t = e - s + 1) > ans) //如果回文长度大于当前大小,则记录
ans = t;
}
return ans;
}
int main()
{
//str[0] = '$';
cin >> n;
while(n--)
{
//scanf("%s",str+1);
scanf("%s",str); //输入字符串
cout << calcul(str) << endl;
}
return 0;
}