这个题目求某个字符串中含的最长的回文子串。
就是一个很简单的LCS模型吗,而且我不明白为什么网上这么多人都说仿照某写法把字符串先逆序一下,然后求LCS,我只想问一下,有必要吗?
直接按LCS的套路来就行了啊,只不过方式变了下,按上面的写法,又麻烦,又根本没利用的LCS的精髓思想
即,先从间隔0位开始做起,然后是间隔1位。。2.。。n-1位,d[i][j]代表i到j的最长回文串个数
于是就有 s[i]==s[j] d[i][j]=d[i+1][j-1]+2,否则就取 max(f[i+1][j],f[i][j-1]),不就行啦。还用得着上面那样搞?
不过如果这个问题这么简单我也不会放到博客里来写了。主要是下面的问题,我还确实一开始没想到。
比较麻烦的是当出现多个情况的时候 输出字典序小的,我一开始没想谨慎,很快的敲了,用个数组直接记录子串的字母的ASCII码值和,比较这个和来确定字典序,后来WA了几次才醒悟,这里肯定不能简单求ASCII和啊,比如 一个字符串里同时存在 adda和bccb,按我的做法,不是任意输出一个都行、、、显然不对嘛
所以这个还是直接在计算的过程中,就把字符串求出来比较好,即按上面的推法,如果s[i]==s[j],把s[i]+已有回文串+s[j]组成新串即可,但是有个问题是,没有字符串函数是可以进行字符串的连接重组的,难道手写?还好C++的string是很强大的,直接可以进行+操作,并且可以直接进行比值,比出来直接就是字典序,那简直方便得不得了啊。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #define INF 1<<30 using namespace std; int d[1010][1010]; double cnt[1010][1010]; string str[1010][1010]; char s[1010]; int len; //void print(int l,int r) //{ // if (l>r) return; // if (s[l]==s[r]) // { // printf("%c",s[l]); // print(l+1,r-1); // if (l<r) // printf("%c",s[r]); // return; // } // if (d[l+1][r]>d[l][r-1]) // { // print(l+1,r); // return; // } // if (d[l+1][r]<d[l][r-1]) // { // print(l,r-1); // return; // } // if (d[l+1][r]==d[l][r-1]) // { // if (cnt[l+1][r]<cnt[l][r-1]) // { // print(l+1,r); // } // else // print(l,r-1); // } // //} int main() { while (scanf("%s",&s)!=EOF) { len=strlen(s); memset(d,0,sizeof d); // memset(cnt,0,sizeof cnt); for (int i=0;i<len;i++) { for (int j=0;j+i<len;j++) { int k=j+i; int chj=s[j]; int chk=s[k]; if (s[j]==s[k]) { if (i==0) { d[j][k]=1; str[j][k]=s[j]; } else{ d[j][k]=d[j+1][k-1]+2; str[j][k]=s[j]+str[j+1][k-1]+s[k]; } } else { if (d[j][k-1]>d[j+1][k]) { d[j][k]=d[j][k-1]; str[j][k]=str[j][k-1]; } else if (d[j][k-1]<d[j+1][k]) { d[j][k]=d[j+1][k]; str[j][k]=str[j+1][k]; } else if (d[j][k-1]==d[j+1][k]) { d[j][k]=d[j+1][k]; if (str[j][k-1]<str[j+1][k]) //直接string进行比值操作就可知道字典序大小 str[j][k]=str[j][k-1]; else str[j][k]=str[j+1][k]; } } } } cout<<str[0][len-1]<<endl;//直接输出该string即可 //print(0,len-1); //printf(" "); } return 0; }