第九章 动态规划 part16(编辑距离专题)583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇

第五十八天| 第九章 动态规划 part16(编辑距离专题)583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇

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

  • 题目链接:https://leetcode.cn/problems/delete-operation-for-two-strings/

  • 题目介绍:

    • 给定两个单词 word1word2 ,返回使得 word1word2 相同所需的最小步数

      每步 可以删除任意一个字符串中的一个字符。

      示例 1:

      输入: word1 = "sea", word2 = "eat"
      输出: 2
      解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"
      
  • 思路:

    • (1)确定dp数组及下标含义:

      • dp[i][j]:表示的是想要让以下标i-1为结尾的s和以下标j-1为结尾的t相同所需要的最小步数。
        
    • (2)确定递推公式:

      • 情况一:s[i-1] == t[j-1]

        • 也就意味着这两个元素我不需要删除,即dp[i][j] = dp[i-1][j-1];
          
      • 情况二:s[i-1] != t[j-1],第二种情况中有三种可能,比较这三种可能的最小值

        • 可能一:删除s[i-1]

          • dp[i][j] = dp[i][j-1] + 1;
            
        • 可能二:删除t[j-1]

          • dp[i][j] = dp[i][j-1] + 1;
            
        • 可能三:同时删除s[i-1]和t[j-1]

          • dp[i][j] = dp[i-1][j-1] + 2;
            
        • 因此, dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 2);
          
    • (3)初始化dp数组:

      • dp[i][0]:表示的是想要让下标为i-1为结尾的s和下标为-1为结尾的t(下标为-1为结尾的t的含义就是t是空串)相同所需要的最小步数。这个最小步数就是i
        
      • dp[0][j]:同理,这个最小步数就是j
        
    • (4)确定遍历顺序:正序

  • 代码:

class Solution {
    public int minDistance(String word1, String word2) {
        char[] char1 = word1.toCharArray();
        char[] char2 = word2.toCharArray();
        // (1)确定dp数组及下标含义
        // dp[i][j]:表示的是想要让以下标i-1为结尾的s和以下标j-1为结尾的t相同所需要的最小步数。
        int[][] dp = new int[char1.length+1][char2.length+1];
        // (3)初始化dp数组:
        // dp[i][0]:表示的是想要让下标为i-1为结尾的s和下标为-1为结尾的t(下标为-1为结尾的t的含义就是t是空串)相同所需要的最小步数。这个最小步数就是i
        // dp[0][j]:同理,这个最小步数就是j
        for (int i = 0; i <= char1.length; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= char2.length; j++) {
            dp[0][j] = j;
        }
        // (4)确定遍历顺序:
        // 正序
        for (int i = 1; i <= char1.length; i++) {
            for (int j = 1; j <= char2.length; j++) {
                // (2)确定递推公式:
                // 分为两种情况:
                // 第一种:s[i-1] == t[j-1],也就意味着这两个元素我不需要删除,即dp[i][j] = dp[i-1][j-1];
                // 第二种:s[i-1] != t[j-1]
                // 第二种情况中有三种可能,比较这三种可能的最小值
                // 可能一:删除s[i-1]    dp[i-1][j] + 1
                // 可能二:删除t[j-1]    dp[i][j-1] + 1
                // 可能三:同时删除s[i-1]和t[j-1]    dp[i-1][j-1] + 2
                // dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 2);
                if (char1[i-1] == char2[j-1]) {
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    dp[i][j] = Math.min(dp[i-1][j] + 1, Math.min(dp[i][j-1] + 1, dp[i-1][j-1] + 2));
                }
            }
        }
        return dp[char1.length][char2.length];
    }
}

二、72. 编辑距离

  • 题目链接:https://leetcode.cn/problems/edit-distance/

  • 题目介绍:

    • 给你两个单词 word1word2请返回将 word1 转换成 word2 所使用的最少操作数

      你可以对一个单词进行如下三种操作:

      • 插入一个字符
      • 删除一个字符
      • 替换一个字符

      示例 1:

      输入:word1 = "horse", word2 = "ros"
      输出:3
      解释:
      horse -> rorse (将 'h' 替换为 'r')
      rorse -> rose (删除 'r')
      rose -> ros (删除 'e')
      
  • 思路:

    • (1)确定dp数组及下标含义:

      • dp[i][j]:表示的是以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,最近编辑距离为dp[i][j]。
        
    • (2)确定递推公式:

      • 情况一:s[i-1] == t[j-1]

        • 既然当前位置都相等,那么dp[i][j] = dp[i-1][j-1];
          
      • 情况二:s[i-1] != t[j-1],如果不相等,题目中提供了三种方式让它们相等,分别是增删改

        • 操作一:删除s[i-1]

          • dp[i][j] =  dp[i-1][j] + 1;
            
        • 操作二:删除t[j-1]

          • dp[i][j] = dp[i][j-1] + 1;
            
        • 操作三:替换s[i-1]或者t[j-1]

          • 替换之后s[i-1] == t[j-1],根据前面的递推公式相等之后dp[i][j] = dp[i-1][j-1]。那么这里我多加了一步替换的操作,因此这里的dp[i][j] = dp[i-1][j-1] + 1。
            
        • 为什么没有添加的操作呢?

          • 因为删除和添加互为逆操作,也就是说,删除s[i-1]就相当于添加t[j],删除t[j-1]就相当于添加s[i]。
        • 因此,dp[i][j] = Math.min(Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 1);
          
    • (3)初始化dp数组:

      • 和"两个字符串的删除操作"那道题一样,
        	第一行dp[0][j]表示空串和t比较,t删除j个元素就能得到,dp[0][j] = j;
        	第一列dp[i][0]表示s和空串比较,s删除i个元素就能得到,dp[i][0] = i;
        
    • (4)确定遍历顺序:正序

  • 代码:

class Solution {
    public int minDistance(String word1, String word2) {
        char[] char1 = word1.toCharArray();
        char[] char2 = word2.toCharArray();
        // (1)确定dp数组及下标含义:
        // dp[i][j]:表示的是以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,最近编辑距离为dp[i][j]。
        int[][] dp = new int[char1.length+1][char2.length+1];
        // (3)初始化dp数组:
        // 和"两个字符串的删除操作"那道题一样,
        // 第一行dp[0][j]表示空串和t比较,t删除j个元素就能得到,dp[0][j] = j;
        // 第一列dp[i][0]表示s和空串比较,s删除i个元素就能得到,dp[i][0] = i;
        for (int i = 0; i <= char1.length; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= char2.length; j++) {
            dp[0][j] = j;
        }
        // (4)确定遍历顺序:正序
        for (int i = 1; i <= char1.length; i++) {
            for (int j = 1; j <= char2.length; j++) {
                // (2)确定递推公式:
                // 分两种情况:
                // 第一种:s[i-1] == t[j-1],既然当前位置都相等,那么dp[i][j] = dp[i-1][j-1];
                // 第二种:s[i-1] != t[j-1]
                // 如果不相等,题目中提供了三种方式让它们相等,分别是增删改
                // 操作一:删除s[i-1]    dp[i-1][j] + 1
                // 操作二:删除t[j-1]    dp[i][j-1] + 1
                // 操作三:替换s[i-1]或者t[j-1]    替换之后s[i-1] == t[j-1],根据前面的递推公式相等之后dp[i][j] = dp[i-1][j-1]。那么这里我多加了一步替换的操作,因此这里的dp[i][j] = dp[i-1][j-1] + 1。
                // 为什么没有添加的操作呢?因为删除和添加互为逆操作,也就是说,删除s[i-1]就相当于添加t[j],删除t[j-1]就相当于添加s[i]。
                // 所以根据这三种操作得出的dp[i][j]如下:
                // dp[i][j] = Math.min(Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 1);
                if (char1[i-1] == char2[j-1]) {
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    dp[i][j] = Math.min(Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 1);
                }
            }
        }
        return dp[char1.length][char2.length];
    }
}

三、编辑距离类问题总结

  • 都是需要分为两种情况
    • 情况一:s[i-1] == t[j-1]
    • 情况二:s[i-1] != t[j-1]
  • 最终的结果都是在dp数组的右下角
    • 只要是通过dp数组的上方或者左方,也就是不单从左上角得到当前的,最终结果都在dp数组右下角

你可能感兴趣的:(动态规划,算法)