最长回文子序列---DP

问题描述

给定一个字符串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  4
1 0 1  2  3
2 0 0 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];

}
原文地址:https://www.cnblogs.com/laysfq/p/12930942.html