4.最长回文子序列----动态规划

解题思路:

状态
f[i][j] 表示 s 的第 i 个字符到第 j 个字符组成的子串中,最长的回文序列长度是多少。

转移方程
如果 s 的第 i 个字符和第 j 个字符相同的话
f[i][j] = f[i + 1][j - 1] + 2
如果 s 的第 i 个字符和第 j 个字符不同的话
f[i][j] = max(f[i + 1][j], f[i][j - 1])
然后注意遍历顺序,i 从最后一个字符开始往前遍历,j 从 i + 1 开始往后遍历,这样可以保证每个子问题都已经算好了。

初始化
f[i][i] = 1 单个字符的最长回文序列是 1

结果
f[0][n - 1]
class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] f = new int[n][n];
        for (int i = n - 1; i >= 0; i--) {
            f[i][i] = 1;
            for (int j = i + 1; j < n; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    f[i][j] = f[i + 1][j - 1] + 2;
                } else {
                    f[i][j] = Math.max(f[i + 1][j], f[i][j - 1]);
                }
            }
        }
        return f[0][n - 1];
    }
}
 
class Solution {
    public int longestPalindromeSubseq(String s) {
        /*
            bb aa bb
            bb a  bb
            dp[i][j] 表示 第 i 个字符到 第 j 个字符之间最长的回文子序列长度
            1、当 s[i] == s[j] 时,考虑 i 和 j 中间序列的奇偶个数, dp[i][j] = dp[i+1][j-1] + 2
            对上述 dp[i][j] =  dp[i+1][j-1] + 2 的解释:
            当序列为 b aa b 时, i = 0, j = 3,则 dp[0][3] = dp[1][2] + 2 = 4
            当序列为 b a b 时,i = 0, j = 2,则 dp[0][2] = dp[1][1] + 2 = 3 
            当序列为 b b 时, i = 0, j = 1,则 dp[0][1] = dp[1][0] = 0 + 2 = 2 (dp[1][0] 默认值为 0)
            该式子同时考虑到了奇偶
            2、当 s[i] != s[j] ,那么 dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1])
            对上述 dp[i][j] 式子的解释:
            假如序列为 d c b c c(index:0-4),s[0] != s[4] ,则 dp[0][4] = Math.max(dp[0][3],dp[1,4]) = Math.max(2,3) = 3

            注意:上述按我习惯分析是将 i 放在了 j 的前面,而按我写法习惯这里是将 i 放在了 j 的后面,即上面的 dp[i][j] 在这里应该是 dp[j][i]
            两层 for 循环,令 i 从 0 遍历到 len-1,而 j 为 i-1 递减到 0
            假如 i = 5,那么 j 的顺序为 4 3 2 1 0,在得到 dp[0][5] 过程中,dp[1][5]等值 就已经提前准备好了,有预先值
            一个字符单独作为一个回文子序列,即 dp[i][i] = 1
        */

        int len = s.length();
        int[][] dp = new int[len][len];
       
        for(int i = 0; i < len; i++){
            dp[i][i] = 1;
            for(int j = i - 1; j >= 0; j--){
                if(s.charAt(i) == s.charAt(j)){
                    dp[j][i] = dp[j+1][i-1] + 2;
                }else{
                    dp[j][i] = Math.max(dp[j+1][i],dp[j][i-1]);
                }
            }
        }
        return dp[0][len-1];
    }
}
原文地址:https://www.cnblogs.com/manmanchanglu/p/12577257.html