【动态规划总结】 【tag4】字符串dp

本专题【动态规划总结】将主要分为4个部分,主要参考leetcode用户(fun4leetcode)对该类问题的总结,并添加自己的个人理解所作。

问题抽象

问题描述

该类问题主要是在解决在String上的动态规划问题。

通用方法

 模板分别代表了在单个字符串的dp和多个字符串dp的不同形式,大部分算法的复杂度在o(n^2)
// i - indexing string s1
// j - indexing string s2
for (int i = 1; i <= n; ++i) {
   for (int j = 1; j <= m; ++j) {
       if (s1[i-1] == s2[j-1]) {
           dp[i][j] = /*code*/;
       } else {
           dp[i][j] = /*code*/;
       }
   }
}
for (int l = 1; l < n; ++l) {
   for (int i = 0; i < n-l; ++i) {
       int j = i + l;
       if (s[i] == s[j]) {
           dp[i][j] = /*code*/;
       } else {
           dp[i][j] = /*code*/;
       }
   }
}

示例题目

  1. Longest Palindromic Subsequence
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];
        for (int i = 0;i < dp.length;i++){
            dp[i][i] = 1;
        }
        for (int l = 1; l < n;l++){
            for (int i = 0;i < n - l;i++){
                int j = i + l;
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] += 2;
                    if (i + 1 <= j - 1){
                        dp[i][j] += dp[i + 1][j - 1];
                    }
                }else{
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[0][n - 1];

    }

1、字符串i到j的通用遍历方法
2、看到一个评论说 求最长回文子串问题 = 判断字符串和其逆序串的LCS问题。非常有理解。
1143. Longest Common Subsequence
字符串dp最经典的问题,是许多进阶问题的基础。
1092. Shortest Common Supersequence
SCS 最长公共超序列 非常难的一道题 难点一部分在于需要对dp值进行操作得到结果 而不是单纯的得到某些值
题目的主要核心思想在于利用LCS求出的dp矩阵得到关系 并通过特殊的遍历手段得到最终值 值得另开一题分析
72. Edit Distance
非常经典的一道dp题目 延伸出了以下思想:
1、部分题目的dp本质上属于暴力求解 对于该题,在对字符的处理上有三种情况:删除 修改 或者在顶部添加 我们不知道哪种操作会接近于最优操作 因此每一个操作都需要记录

    public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        if (m == 0 || n == 0) return Math.max(m,n);
        int[][] dp = new int[m + 1][n + 1];
        dp[1][0] = 1; dp[0][1] = 1;
        for (int i = 1; i <= m;i++){
            dp[i][0] = i;
        }
        for (int i = 1; i <= n;i++){
            dp[0][i] = i;
        }
        for (int i = 1; i <= m;i++){
            for (int j = 1; j <= n;j++){
                dp[i][j] = Math.min(dp[i][j - 1] + 1, dp[i - 1][j] + 1);
                int extra = word1.charAt(i - 1) == word2.charAt(j - 1) ? 0 : 1;
                dp[i][j] = Math.min(dp[i][j], dp[i - 1][j - 1] +extra);
            }
        }
        return dp[m][n];
    }
  1. Distinct Subsequences
    该题主要的运用了反推思想 难度较大。
  2. Minimum ASCII Delete Sum for Two Strings
    该题是lcs题目的变体问题,将dp存储的数量转变为ACSII最大值。
  3. Longest Palindromic Substring
    最长回文串 动态规划不是解决该问题的最好方法。

总结

**该类问题是动态规划过程的常规问题,题目的变化很大,类型较多 总结了以下处理原则:
1、考虑最后一个字母 处理时关注于最后一个字母与之前dp的关系
2、考虑 m * n的全部遍历
3、LCS SCS 是基本和进阶的两个问题,特别是LCS 许多问题的变体都是由该问题得到。
**

posted @ 2020-12-06 16:07  backTraced  阅读(128)  评论(0)    收藏  举报