区间类DP

DP做的我烦躁啊。


  • 求一段区间的解 min/max/count

  • 相比划分类 DP ,区间类 DP 为连续相连的 subproblem ,中间不留空,更有 divide & conquer 的味道。

  • 转移方程通过区间更新

  • 从大到小的更新


Matrix-chain multiplication (算法导论)

  • 给定矩阵向量 [A1, A2, A3 .. An]

  • 矩阵乘法有结合律,所以任意的 parenthesization 结果一样

  • Dimension (a x b) 乘 (b x c) 得到 (a x c) ,总计算量为 a x b x c

  • 可能的括号加法为 Catalan 数,O(2^n),因而搜索不合适。

  • 让 dp[i][j] 代表(i , j) 区间内最优的括号顺序运算次数

  • 符合 optimal substructure,反证法

  • A = rows * cols,假如从 k 分开左右 i <= k < j ,如下 k = 5 时:

  • [A1, A2, A3, A4, A5 || A6, A7,A8,A9]

  • 左子问题为 A1.rows x A5.cols

  • 右子问题为 A6.rows x A9.cols

  • 其中 A5.cols = A6.rows

  • 其总花费为 dp[1,5] + dp[6,9] + A1.rows A5.cols A9.cols

至此,对于任意 size (i , j) 的向量区间,我们都可以遍历所有合理 k 的切分点,实现记忆化的 divide & conquer,当前区间的最优解一定由其最优子区间拼接而成。

子问题图如下。其实就是一个 n x n 的矩阵对角线,代表所有的子区间。

132. Palindrome Partitioning II

上一题的求所有区间最优解进行拼接的思路和 optimal substructure 结构和这题非常像,再贴一遍,感受一下。

不过 Matrix Chain Multiplication 要比这个复杂,时间复杂度为 O(n^3). 毕竟每个切点上会生成两个 subproblems.

public class Solution {
    public int minCut(String s) {
        if(s == null || s.length() <= 1) return 0;
        int len = s.length();

        boolean[][] isPalindrome = new boolean[len][len];
        int[] dp = new int[len];

        for(int i = 0; i < len; i++){
            dp[i] = i;
            for(int j = 0; j <= i; j++){
                if(s.charAt(i) == s.charAt(j) && (i - j < 2 || isPalindrome[j + 1][i - 1])){
                    isPalindrome[i][j] = isPalindrome[j][i] = true;
                    if(j == 0){
                        dp[i] = 0;
                    } else {
                        dp[i] = Math.min(dp[i], dp[j - 1] + 1);
                    }
                }
            }
        }

        return dp[len - 1];
    }
}

Valid Palindrome

  • State: f[i][j]表示index从i到j这一段是不是一个回文串
  • Function: f[i][j] = f[i + 1][j - 1] && (s[i] == s[j])
  • Initialize: f[i][i] = true
  • Answer: f[x][y] // x, y是你想查询的那一段区间

注意不要越界,注意初始化。

i 依赖于i + 1,算的时候要倒过来,先算大的。本质上是先for区间长度,再for左端点。

这个valid解法和LC125 Valid Palindrome不一样,因为LC125要忽略空格和符号。这个解法其实实战并没有什么优势,只是区间型动态规划的一个例子。

public class Solution {
    public boolean isPalindrome(String s) {
        if (s == null || s.length() == 0) return true;

        int n = s.length();
        boolean[][] f = new boolean[n][n];

        for (int i = 0; i < n; ++i) {
            f[i][i] = true;
        }

        for (int i = 0; i < n - 1; ++i) {
            f[i][i + 1] = (s.charAt(i) == s.charAt(i + 1));
        }

        for (int i = n - 1; i >= 0; --i) {
            for (int j = i + 2; j < n; ++j) {
                f[i][j] = f[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
            }
        }
        return f[0][n - 1];
    }
}

Stone Game

312. Burst Balloons

87. Scramble String

results matching ""

    No results matching ""