题目大意:求最长回文子串,并输出其中字典序最小的。
思路:转化为LCS。将原来字符串反转,得到str2,然后和原字符串求LCS,求LCS的过程中还需要记录每一个状态所对应的的LCS,因为之后要比较。然后再分两种情况(1)回文串为偶数,那么当str1位置为i时,str2的位置应为len-i。(2)为奇数,那么考虑中间字母为str1[ i ]时,str1的位置为i-1,str2的位置为len-i,这里还需要注意,中间位置要从str[1]开始枚举,因为左、右边可以为空。
很好的题,因为先开始自己想到LCS,但是不会找字典序最小的,原来只要把每个状态d[ i ][ j ] 的s都记录下来就可以了,代码用C++写比较方便,但是对C++不是很熟,代码很多都是照着别人的代码来的。。 = =
代码如下:
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<algorithm> using namespace std; const int MAXN = 1111 ; char str[MAXN]; char str2[MAXN]; struct Node { int len; string s; bool operator < (const Node & tmp) const { if(len == tmp.len) { return s>tmp.s; } else return len<tmp.len; } } d[MAXN][MAXN]; int len; void LCS() { for(int i = 0;i<=len;i++) { d[0][i].len = 0; d[0][i].s.clear(); d[i][0].len = 0; d[i][0].s.clear(); } for(int i = 1;i<=len;i++) { for(int j = 1;j<=len;j++) { if(str[i]==str2[j]) { d[i][j].len = d[i-1][j-1].len+1; d[i][j].s = d[i-1][j-1].s + str[i]; } else { d[i][j] = max(d[i-1][j],d[i][j-1]); } } } } string roll(string s) { string tmp=""; for(int i = s.length()-1;i>=0;i--) tmp += s[i] ; return tmp; } int main() { while(cin>>(str+1)) { len = strlen(str+1); for(int i = 1;i<=len;i++) { str2[i] = str[len-i+1]; } LCS(); Node ans; ans.len = 0; ans.s.clear(); for(int i = 1;i<len;i++) ans = max(ans,d[i][len-i]); ans.len *= 2; ans.s += roll(ans.s); Node tmp; for(int i = 1;i<=len;i++) { tmp.len = 2*d[i-1][len-i].len+1; tmp.s = d[i-1][len-i].s + str[i] + roll(d[i-1][len-i].s); ans = max(ans,tmp); } cout<<ans.s<<endl; } return 0; }