• 力扣392题、115题、583题、72题(编辑距离)


    392、判断子序列

    基本思想:

    动态规划

    具体实现:

    1.确定dp数组含义

    dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。

    2.确定递推公式

    两种情况

    • if (s[i - 1] == t[j - 1])
      • t中找到了一个字符在s中也出现了,dp[i][j] = dp[i - 1][j - 1] + 1;
    • if (s[i - 1] != t[j - 1])
      • 相当于t要删除元素,继续匹配,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了
      • dp[i][j] = dp[i][j - 1]

    3.dp数组如何初始化

    从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1] 和 dp[i][j - 1],所以要初始化dp[0][0]和dp[i][0]

    根据定义推出dp[i][0]和dp[0][j]是没有含义的,所以初始化为0

    4.确定遍历顺序

    从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1] 和 dp[i][j - 1],那么遍历顺序也应该是从上到下,从左到右

    5.举例

    代码:

    class Solution {
        public boolean isSubsequence(String s, String t) {
            int length1 = s.length();
            int length2 = t.length();
            int[][] dp = new int[length1+1][length2+1];
            for(int i = 1; i <= length1; i++){
                for(int j = 1; j <= length2; j++){
                    if(s.charAt(i - 1) == t.charAt(j - 1)){
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    } else {
                        dp[i][j] = dp[i][j - 1];
                    }
                }
            }
            if(dp[length1][length2] == length1){
                return true;
            } else {
                return false;
            }
        }
    }

    115、不同的子序列

    基本思想:

    动态规划

    具体实现:

    1.确定dp数组(dp table)以及下标的含义

    dp[i][j]:以i-1为结尾的s子序列(s子序列里有i个字符)中出现以j-1为结尾的t子序列(t子序列中有j个字符)的个数为dp[i][j]

    2.确定递推公式s:bagg 和 t:bag,i=4.j=3

    • s[i-1]=t[j-1],s[3] =t[2],dp[i][j]有两部分组成,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 
      • 用s[i-1]来匹配,让 s 中 [0,i-1]个字符(bagg)去匹配 t 中的 [0,j−1] 字符(bag)
        • 因为s[i-1]=t[j-1],s[3] =t[2],所以个数为s[0到i-2]和t[0到j-2]匹配结果dp[i - 1][j - 1]。去匹配bag和ba,s 中 [0,i-2],t 中的 [0,j−2]
        • 用s[3]来匹配,即:s[0]s[1]s[3]组成的bag。
      • 一部分是不用s[i - 1]来匹配,让 s 中 [0,i-2] (bag)个字符去匹配 t 中的 [0,j-1]字符(bag),
        • 个数为dp[i - 1][j]。字符串s不用s[3]来匹配,即用s[0]s[1]s[2]组成的bag。
    • s[i]!=t[j]dp[i][j]只有一部分组成,dp[i - 1][j]
      • 不用s[i ]来匹配,即:dp[i - 1][j]

    3.初始化

    dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。

    dp[i][0]都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1。

    dp[0][j]:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数。

    dp[0][j]都是0,s如论如何也变成不了t。

    dp[0][0]=1,空字符串s,可以删除0个元素,变成空字符串t。

    代码:

    class Solution {
        public int numDistinct(String s, String t) {
            int[][] dp = new int[s.length() + 1][t.length() + 1];
            for (int i = 0; i < s.length() + 1; i++) {
                dp[i][0] = 1;
            }
            
            for (int i = 1; i < s.length() + 1; i++) {
                for (int j = 1; j < t.length() + 1; j++) {
                    if (s.charAt(i - 1) == t.charAt(j - 1)) {
                        dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                    }else{
                        dp[i][j] = dp[i - 1][j];
                    }
                }
            }
            
            return dp[s.length()][t.length()];
        }
    }

    583、两个字符串的删除操作

    基本思想:

    与上一题不同的地方是两个字符串都可以删除

    具体实现:

    1.确定dp数组以及下标的含义

    dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。

    2.确定递推公式

    (1)当word1[i - 1] 与 word2[j - 1]相同的时候,dp[i][j] = dp[i - 1][j - 1];

    (2)当word1[i - 1] 与 word2[j - 1]不相同的时候,有三种情况:

      情况1:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1

      情况2:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1

      情况3:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2

      取最小值dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

    3.dp数组如何初始化

    dp[i][0]:word2为空字符串,以i-1为结尾的字符串word1要删除多少个元素,才能和word2相同,

    所以dp[i][0] = i。

    dp[0][j]同理

    4.确定遍历顺序

    从上到下,从左到右

    5.举例推导dp数组

    代码:

    class Solution {
        public int minDistance(String word1, String word2) {
            int[][] dp = new int[word1.length() + 1][word2.length() + 1];
            for (int i = 0; i < word1.length() + 1; i++) dp[i][0] = i;
            for (int j = 0; j < word2.length() + 1; j++) dp[0][j] = j;
            for (int i = 1; i < word1.length() + 1; i++) {
                for (int j = 1; j < word2.length() + 1; j++) {
                    if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                        dp[i][j] = dp[i - 1][j - 1];
                    } else {
                        dp[i][j] = Math.min(dp[i - 1][j - 1] + 2,Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
                    }
                }
            }
            return dp[word1.length()][word2.length()];
        }
    }

    72、编辑距离

    基本思想:

    动态规划

    具体实现:

    1.确定dp数组以及下标的含义

    dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。

    2.确定递推公式

    A.  word1[i - 1] == word2[j - 1]

    不用任何编辑,dp[i][j] = dp[i - 1][j - 1];

    B.  word1[i - 1] != word2[j - 1]

    (1)word1删除一个元素

    以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。

    举例:

                      i-2  i-1                      j-1

    word1 = ab c    d        word2=abc

    2)word2删除一个元素

    以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。

    word2删除一个元素相当于word1添加一个元素

                      i-1                       j-2 j-1

    word1 = ab c         word2=abc   d

    word1为"abc",word2为"abcd",

    他俩变得一样的话word2删除一个d的操作和word1添加一个操作数一样

    (3)替换元素

    word1替换word1[i-1],使其与word2[j - 1]相同,此时不用增加元素

    以下标i - 2为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。

                     i-2   i-1                 j-2  j-1

    word1 = abc    s     word2=abc   d

    3.dp数组如何初始化

     dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。

    dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i;

    同理dp[0][j] = j;

    4.遍历顺序

    从左到右,从上到下

    5.举例

    代码:

    class Solution {
        public int minDistance(String word1, String word2) {
            int m = word1.length();
            int n = word2.length();
            int[][] dp = new int[m+1][n+1];
            for (int i = 1; i <= m; i++) dp[i][0] = i;
            for (int j = 1; j <= n; j++) dp[0][j] = j;
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= n; j++) {
                    if (word1.charAt(i - 1) == word2.charAt(j - 1)){
                        dp[i][j] = dp[i - 1][j - 1];
                    } else {
                        dp[i][j] = Math.min(Math.min(dp[i - 1][j],dp[i][j - 1]),dp[i - 1][j - 1]) + 1;
                    }
                }
            }
            return dp[m][n];
        }
    }
  • 相关阅读:
    Nginx+Lua系列:Nginx api for lua
    Twemproxy 代理Redis集群
    Nginx+Lua系列:安装配置Nginx+Lua环境
    Nginx配置http2
    双杀 0day 漏洞(CVE-2018-8174)复现
    Restful 和 Rpc
    合作共赢
    package.json 配置发布到私有仓库
    Ant-design-vue form 表单错误提示在 输入框为 large 时 会撑开 排版样式
    献血 组织
  • 原文地址:https://www.cnblogs.com/zhaojiayu/p/15721238.html
Copyright © 2020-2023  润新知