题目描述
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同。如abba和yyxyy。在判断回文时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独的一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。
输入
一行字符串,字符串长度不超过5000。
输出
字符串中的最长回文子串。
样例输入 Copy
Confuciuss say:Madam,I'm Adam.
样例输出 Copy
Madam,I'm Adam
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int p[5005], cnt, maxstart, maxend;//保存小写后每个字母在原来字符串的位置
string lower(string s) { //保存只有小写的串并计算出p数组
string low = "";
int len = s.length();
cnt = 0;
for(int i = 0; i < len; i++) {
if((s[i] >= 'A' && s[i] <= 'Z')||(s[i] >= 'a' && s[i] <= 'z')||(s[i] >= '0' && s[i] <= '9')) {
if(s[i] >= 'A' && s[i] <= 'Z') {
low.push_back(s[i] + 32);
} else {
low.push_back(s[i]);
}
p[cnt++] = i;
}
}
return low;
}
void cal(string low) {
int len = low.length();
int dp[len][len];//i到j是否是回文串的标记数组
memset(dp, 0, sizeof(dp));
int ans = -1;//最长回文串长度
maxstart = 0, maxend = 0;
for(int i = 0; i < len; i++) {
dp[i][i] = 1;
if(i < len - 1) {
if(low[i] == low[i + 1]) {
dp[i][i + 1] = 1;
if(ans < 2) {
ans = 2;
maxstart = i;
maxend = i + 1;
}
}
}
}
for(int L = 3; L <= len; L++) { //枚举字串的长度
for(int i = 0; i + L - 1 < len; i++) { //枚举字串的起始端点
int j = i + L - 1;//字串右端点
if(low[i] == low[j] && dp[i + 1][j - 1] == 1) {
dp[i][j] = 1;
if(ans < L) {
ans = L;
maxstart = i;
maxend = j;
}
}
}
}
}
int main(int argc, char** argv) {
string s;
while(getline(cin, s)) {
memset(p, -1, sizeof(p));
string low = lower(s);
cal(low);
for(int i = p[maxstart]; i <= p[maxend]; i++) {
cout << s[i];
}
cout << endl;
}
return 0;
}