动态规划真的懂了呀系列《区间DP:最长回文子序列》

77 阅读2分钟

价值:记录学习过程的思考,本身就是一场动态规划的前生,记忆化搜索。

Problem: 516. 最长回文子序列

//f[i][j] = [i~j] 最长的回文子序列
//分类
//如果1: arr[i] == arr[j] ; f[i][j] = f[i+1][j-1]+2 
//如果2: arr[i] != arr[j] ; f[i][j] = max(f[i+1][j],f[i][j-1]) //(左边在结果集或右边在结果集, 取max) 
//取答案:max每个分类的结果:f[i][j] = max(f[i+1][j-1]+2, max(f[i+1][j],f[i][j-1])) 
class Solution {
    public int longestPalindromeSubseq(String s) {
        char[] arr = s.toCharArray();

        // f[i][j] = i~j最长的回文子序列
        // arr[i] == arr[j] ; f[i][j] = f[i+1][j-1]+2
        // arr[i] != arr[j] ; f[i][j] = max(f[i+1][j],f[i][j-1])
        // f[i][j] = max(f[i+1][j-1]+2,max(f[i+1][j],f[i][j-1]))

        int n = arr.length;

        int[][] dp = new int[n][n];

        // 【j : 0 ~ n-1】
        // 起点 ->【j,j】->扩展 [j,j+1] -> 扩展 [j-1,j+1]
        // i 往左边走, j 往右边走,
        // init:j = 0 ,i = j-1 ;
        // 顺序 整体上从左往右遍历
        for (int j = 0; j < n; j++) {
            // 递归边界 dfs(j,j) = 1
            dp[j][j] = 1;
            // (j+1,j)交叉 i = j+1 ,dfs(j+1,j) = 0,这里就是为什么i从j-1开始
            for (int i = j - 1; i >= 0; i--) {
                if (arr[i] == arr[j]) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[0][n - 1];
    }

    public int longestPalindromeSubseq1(String s) {
        char[] arr = s.toCharArray();
        // f[i][j] = i~j最长的回文子序列
        // arr[i] == arr[j] ; f[i][j] = f[i+1][j-1]+2
        // arr[i] != arr[j] ; f[i][j] = max(f[i+1][j],f[i][j-1])
        // f[i][j] = max(f[i+1][j-1]+2,max(f[i+1][j],f[i][j-1]))
        int n = arr.length;
        int[][] dp = new int[n][n];
        // 【i : n-1 ~ 0】
        // 起点 ->【i,i】->扩展 [i,j] -> 扩展 [i-1,j+1]
        // i 往左边走, j 往右边走,
        // init: i = n-1, j = i+1,
        // 顺序 整体上从右往左遍历
        for (int i = n - 1; i >= 0; i--) {
            // 递归边界 dfs(i,i) = 1
            dp[i][i] = 1;
            //(i,i-1)交叉:j = i-1 : dfs(i,i-1) = 0,这里就是为什么j从i+1开始
            for (int j = i + 1; j < n; j++) {
                if (arr[i] == arr[j]) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[0][n - 1];
    }
}