算法奇妙屋(二十一)-两个数组或字符串的dp问题(动态规划)

文章目录

一. 力扣 1143. 最长公共子序列

1. 题目解析

题目很好理解, 这里简单提一下

2. 算法原理

细节点很多, 但不用慌, 图解都已点明

3. 代码

java 复制代码
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        // 建表/初始化
        int m = text1.length();
        int n = text2.length();
        String s1 = " " + text1;
        String s2 = " " + text2;
        int[][] dp = new int[m + 1][n + 1];
        // 填表
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (s1.charAt(i) == s2.charAt(j)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else {
                    dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
                }
            }
        }
        return dp[m][n];
    }
}

二. 力扣 1035. 不相交的线

1. 题目解析

但看题干有点抽象, 但是结合示例之后, 会有新的发现

2. 算法原理

原理与上一道题一模一样, 这里带大家简单回忆一下

3. 代码

java 复制代码
class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        // 建表/初始化
        int m = nums1.length;
        int n = nums2.length;
        int[][] dp = new int[m + 1][n + 1];
        // 填表
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[m][n];
    }
}

三. 力扣 115. 不同的子序列

1. 题目解析

题目很短, 也很好理解, 我们简单分析下

2. 算法原理

这里细节部分较多, 很多原因我们要搞清楚, 这里图解我都做了标记

3. 代码

第一个是对应上面图解的部分
第二个是进一步细分的代码, 即我们不初始化dp表, 直接在填表的时候进行判断, 如果为第一行, 结果是用已经确定的一个子序列+从s的[0,j-1]区间符合条件的子序列个数

java 复制代码
class Solution {
    public int numDistinct(String ss, String tt) {
        // 建表
        int n = ss.length();
        int m = tt.length();
        String s = " " + ss;
        String t = " " + tt;
        int[][] dp = new int[m + 1][n + 1];
        // 初始化
        for (int j = 0; j <= n; j++) {
            dp[0][j] = 1;
        }
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = t.charAt(i) == s.charAt(j) ? dp[i - 1][j - 1] + dp[i][j - 1] : dp[i][j - 1];
            }
        }
        return dp[m][n];
    }
}

java 复制代码
class Solution {
    public int numDistinct(String ss, String tt) {
        int n = ss.length();
        int m = tt.length();
        String s = " " + ss;
        String t = " " + tt;
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (i == 1 && t.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i][j - 1] + 1;
                } else {
                    dp[i][j] = t.charAt(i) == s.charAt(j) ? dp[i - 1][j - 1] + dp[i][j - 1] : dp[i][j - 1];
                }
            }
        }
        return dp[m][n];
    }
}

四. 力扣 44. 通配符匹配

1. 题目解析

理解特殊字符的含义和题目要求

2. 算法原理

细节点较多, 有一些优化, 但整体不算太难

3. 代码

java 复制代码
class Solution {
    public boolean isMatch(String ss, String pp) {
        // 建表
        int m = ss.length();
        int n = pp.length();
        String s = " " + ss;
        String p = " " + pp;
        boolean[][] dp = new boolean[m + 1][n + 1];
        // 初始化
        for (int j = 1; j <= n; j++) {
            if (p.charAt(j) == '*') {
                dp[0][j] = true;
            }else {
                break;
            }
        }
        dp[0][0] = true;
        // 填表
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                char ch = p.charAt(j);
                if (ch == '?' || ch == s.charAt(i)) {
                    dp[i][j] = dp[i - 1][j - 1];
                }else if (ch == '*') {
                    dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
                }
            }
        }
        return dp[m][n];
    }
}

五. 力扣 10. 正则表达式匹配

1. 题目解析

题目细节较多, 和上一道题差不多

2. 算法原理

原理与上一道题差不多, 细节方面稍有不同

3. 代码

java 复制代码
class Solution {
    public boolean isMatch(String ss, String pp) {
        // 建表
        int m = ss.length();
        int n = pp.length();
        char[] s = (" " + ss).toCharArray();
        char[] p = (" " + pp).toCharArray();
        boolean[][] dp = new boolean[m + 1][n + 1];
        // 初始化
        dp[0][0] = true;
        for (int j = 2; j <= n; j += 2) {
            if (p[j] == '*') {
                dp[0][j] = true;
            } else {
                break;
            }
        }
        // 填表
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (p[j] != '*' && (s[i] == p[j] || p[j] == '.') && dp[i - 1][j - 1]) {
                    dp[i][j] = true;
                } else if (p[j] == '*') {
                    if (dp[i][j - 2] || (p[j - 1] == s[i] || p[j - 1] == '.') && dp[i - 1][j]) {
                        dp[i][j] = true;
                    }
                }
            }
        }
        return dp[m][n];
    }
}

六. 力扣 97. 交错字符串

1. 题目解析

只看题目感觉有点难, 但是进行分析时发现还是较容易的

2. 算法原理

需要注意, 我们这里考虑的都是三个字符串前面拼接上空格后的状态

3. 代码

java 复制代码
class Solution {
    public boolean isInterleave(String s11, String s22, String s33) {
        // 建表, 特殊处理
        int m = s11.length();
        int n = s22.length();
        if (m + n != s33.length()) {
            return false;
        }
        char[] s1 = (" " + s11).toCharArray();
        char[] s2 = (" " + s22).toCharArray();
        char[] s3 = (" " + s33).toCharArray();
        boolean[][] dp = new boolean[m + 1][n + 1];
        // 初始化
        dp[0][0] = true;
        for (int i = 1; i <= m; i++) {
            if (s1[i] == s3[i]) {
                dp[i][0] = true;
            }else {
                break;
            }
        }
        for (int j = 1; j <= n; j++) {
            if (s2[j] == s3[j]) {
                dp[0][j] = true;
            }else {
                break;
            }
        }
        // 填表
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (s1[i] == s3[i + j] && dp[i - 1][j] || s2[j] == s3[i + j] && dp[i][j - 1]) {
                    dp[i][j] = true;
                }
            }
        }
        return dp[m][n];
    }
}

七. 力扣 712. 两个字符串的最小ASCII删除和

1. 题目解析

2. 算法原理

3. 代码

java 复制代码
class Solution {
    public int minimumDeleteSum(String s11, String s22) {
        // 建表,初始化
        int m = s11.length();
        int n = s22.length();
        char[] s1 = (" " + s11).toCharArray();
        char[] s2 = (" " + s22).toCharArray();
        int[][] dp = new int[m + 1][n + 1];
        // 填表
        for (int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                if (s1[i] == s2[j]) {
                    dp[i][j] = dp[i - 1][j - 1] + s1[i];
                }
                dp[i][j] = Math.max(dp[i][j], Math.max(dp[i][j - 1], dp[i - 1][j]));
            }
        }
        // 返回结果
        int sum = 0;
        for (int i = 1; i <= m; i++) {
            sum += s1[i];
        }
        for (int j = 1; j <= n; j++) {
            sum += s2[j];
        }
        return sum - 2 * dp[m][n];
    }
}

八. 力扣 718. 最长重复子数组

1. 题目解析

题意很好理解, 直接看示例即可, 要注意的是子序列和子数组的关系

2. 算法原理

3. 代码

java 复制代码
class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        // 建表,初始化
        int m = nums1.length;
        int n = nums2.length;
        int[][] dp = new int[m + 1][n + 1];
        //填表
        int ret = 0;
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    ret = Math.max(ret, dp[i][j]);
                }
            }
        }
        return ret;
    }
}
相关推荐
草莓熊Lotso2 小时前
《算法闯关指南:递归,搜索与回溯算法--递归》--04. 两两交换链表中的结点 ,05.Pow(x,n)
数据结构·算法·链表
Bruce_kaizy2 小时前
c++图论——最短路之Johnson算法
开发语言·数据结构·c++·算法·图论
蒙奇D索大2 小时前
【数据结构】排序算法精讲 | 交换排序全解:交换思想、效率对比与实战代码剖析
数据结构·笔记·考研·算法·排序算法·改行学it
sin_hielo2 小时前
leetcode 1351
数据结构·算法·leetcode
睡醒了叭2 小时前
图像分割-传统算法-边缘分割
图像处理·opencv·算法·计算机视觉
AndrewHZ2 小时前
【图像处理基石】有哪些好用的图像去噪算法可以推荐一下么?
图像处理·深度学习·算法·计算机视觉·cv·噪声
雪花desu2 小时前
【Hot100-Java中等】:字母异位词分组
java·算法·leetcode·哈希表
Word码2 小时前
LeetCode283. 移动零(双指针精讲)
算法·leetcode·职场和发展
xiaoxue..2 小时前
二叉搜索树 BST 三板斧:查、插、删的底层逻辑
javascript·数据结构·算法·面试