• 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];
        }
    }
  • 相关阅读:
    【洛谷P3853】 [TJOI2007]路标设置
    【洛谷P1159】排行榜
    【洛谷P2921】[USACO08DEC]在农场万圣节
    【洛谷P1108】低价购买
    【洛谷P1363】幻象迷宫
    【题解】洛谷P2023 [AHOI2009] 维护序列(线段树)
    【数据结构】线段树的几种用法
    【题解】洛谷P1283 平板涂色(搜索+暴力)
    【题解】洛谷P1074 [NOIP2009TG] 靶形数独(DFS+剪枝)
    【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)
  • 原文地址:https://www.cnblogs.com/manmanchanglu/p/12577257.html
Copyright © 2020-2023  润新知