问题描述
给定一个字符串s
,找到其中最长的回文子序列。可以假设s
的最大长度为1000
。
解题思路
1.说明
首先要弄清楚回文子串和回文子序列的区别,如果一个字符串是“bbbab”,那么它的回文子串为“bbb”,但是其回文子序列是“bbbb”,这是因为回文子序列中可以相隔字符,不一定要连续。
2.思路
定义dp数组的含义。这里我们定义一个二维数组dp
dp[i][j]表示字符串str从i到j的字符串中最长回文子序列的长度。
假设我们现在已经知道dp[i+1][j-1]的值,那么dp[i][j]的值只需要判断s[i]和s[j]是否相等即可。
如果s[i]=s[j],那么dp[i][j]=dp[i+1][j-1]+2,直接加2即可。
如果s[i]!=s[j],说明s[i]和s[j]至少是不在这个回文序列的,表明这时的dp[i][j]只需取两者之间的最大值即可,那么dp[i][j]=Max(dp[i][j-1],dp[i+1][j])。
3. 举例说明
例如字符串“bbbab”,在创建数组之前,可以先将如下矩阵的部分内容填好,因为dp[i][i]一个字符即可构成一个回文序列,所以有dp[i][i]=1。同时,dp[i][j](i>j)=0;即不存在。
然后可以从下往上来计算。
ij | 0 | 1 | 2 | 3 | 4 |
0 | 1 | 2 | 2 | 2 | 4 |
1 | 0 | 1 | 2 | 2 | 3 |
2 | 0 | 0 | 1 | 1 | 3 |
3 | 0 | 0 | 0 | 1 | 1 |
4 | 0 | 0 | 0 | 0 | 1 |
填满表格最后的一个数即为回文子序列最长的长度。返回dp[o][4]即可。
3. 代码
int longestPalindromeSubseq(char * s){ int N=strlen(s); int dp[N][N]; //dp[i][j]表示从i到j回文子序列的长度 for(int i=0;i<N;++i){ for(int j=0;j<N;++j){ if(i==j) dp[i][j]=1; else dp[i][j]=0; } } for(int i=N-1;i>=0;--i){ for(int j=i+1;j<N;++j){ if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2; else dp[i][j]=fmax(dp[i][j-1],dp[i+1][j]); } } return dp[0][N-1]; }