代码随想录第四十五天|115.不同的子序列 583. 两个字符串的删除操作 72. 编辑距离

115. 不同的子序列

题目描述

给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
题目数据保证答案符合 32 位带符号整数范围。

解题思路

这个问题同样可以通过动态规划来解决。我们定义一个二维数组 dp,其中 dp[i][j] 表示字符串 s 的前 i 个字符中包含字符串 t 的前 j 个字符的子序列的个数。
递推公式的由来:

  • 当 s 的第 i 个字符(从 1 开始计数)与 t 的第 j 个字符相同时,我们可以选择使用这个字符来匹配 t 的第 j 个字符,或者不使用这个字符。因此,dp[i][j] 应该是 dp[i-1][j-1](使用 s 的第 i 个字符匹配 t 的第 j 个字符)加上 dp[i-1][j](不使用 s 的第 i 个字符)。
  • 当 s 的第 i 个字符与 t 的第 j 个字符不同时,我们不能使用 s 的第 i 个字符来匹配 t 的第 j 个字符,因此 dp[i][j] 应该等于 dp[i-1][j]。
    初始化条件:
  • dp[i][0] 应该为 1,因为任何字符串的子序列中都包含空字符串。
  • dp[0][j] 应该为 0,除非 j 也为 0,因为空字符串不能包含非空字符串作为子序列。
    例子说明:
    假设 s = “rabbbit”,t = “rabbit”。我们要计算 dp[7][6]。
  • dp[7][6] = dp[6][5] + dp[6][6],因为 s 的最后一个字符 ‘t’ 与 t 的最后一个字符 ‘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(); i++) {
            dp[i][0] = 1;
        }
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); 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. 两个字符串的删除操作

题目描述

给定两个单词 word1word2,找到使得 word1word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
示例:

  • 输入: “sea”, “eat”
  • 输出: 2
  • 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea"

解题思路

这个问题可以通过动态规划来解决。我们定义一个二维数组 dp,其中 dp[i][j] 表示将字符串 word1 的前 i 个字符和字符串 word2 的前 j 个字符转换为相同字符串所需的最小删除操作数。
递推公式的由来:

  • word1 的第 i 个字符(从 1 开始计数)与 word2 的第 j 个字符相同时,我们不需要进行任何删除操作,因此 dp[i][j] 应该等于 dp[i-1][j-1]
  • word1 的第 i 个字符与 word2 的第 j 个字符不同时,我们有三种选择:
    1. 删除 word1 的第 i 个字符,此时操作数增加 1,即 dp[i-1][j] + 1
    2. 删除 word2 的第 j 个字符,此时操作数增加 1,即 dp[i][j-1] + 1
    3. 同时删除 word1 的第 i 个字符和 word2 的第 j 个字符,此时操作数增加 2,但这种情况不是最优的,因为我们总是可以选择删除一个字符来达到相同的效果。
      因此,我们只需要在删除 word1 的第 i 个字符和删除 word2 的第 j 个字符中选择操作数较少的一个,即 dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1
      初始化条件:
  • dp[i][0] 应该等于 i,因为将 word1 的前 i 个字符转换为空字符串需要删除 i 个字符。
  • dp[0][j] 应该等于 j,因为将空字符串转换为 word2 的前 j 个字符需要插入 j 个字符,但在这个问题中我们只考虑删除操作,所以初始化为 j

代码

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(); i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i <= word2.length(); i++) {
            dp[0][i] = i;
        }
        for (int i = 1; i <= word1.length(); i++) {
            for (int j = 1; j <= word2.length(); 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], dp[i][j - 1]) + 1;
                }
            }
        }
        return dp[word1.length()][word2.length()];
    }
}

72. 编辑距离

题目描述

给你两个单词 word1word2,请你计算出将 word1 转换成 word2 所使用的最少操作数。
你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符
    示例 1:
  • 输入:word1 = "horse", word2 = "ros"
  • 输出:3
  • 解释:horse -> rorse (将 'h' 替换为 'r') -> rose (删除 'r') -> ros (删除 'e')
    示例 2:
  • 输入:word1 = "intention", word2 = "execution"
  • 输出:5
  • 解释:intention -> inention (删除 't') -> enention (将 'i' 替换为 'e') -> exention (将 'n' 替换为 'x') -> exection (将 'n' 替换为 'c') -> execution (插入 'u')

解题思路

这个问题可以通过动态规划来解决。我们定义一个二维数组 dp,其中 dp[i][j] 表示将字符串 word1 的前 i 个字符转换为字符串 word2 的前 j 个字符所需的最少操作数。
递推公式的由来:

  • word1 的第 i 个字符与 word2 的第 j 个字符相同时,我们不需要进行任何操作,因此 dp[i][j] 应该等于 dp[i-1][j-1]
  • word1 的第 i 个字符与 word2 的第 j 个字符不同时,我们有三种选择:
    1. 插入操作:在 word1 中插入一个字符以匹配 word2 的第 j 个字符,此时操作数增加 1,即 dp[i][j-1] + 1
    2. 删除操作:删除 word1 的第 i 个字符,此时操作数增加 1,即 dp[i-1][j] + 1
    3. 替换操作:将 word1 的第 i 个字符替换为 word2 的第 j 个字符,此时操作数增加 1,即 dp[i-1][j-1] + 1
  • 因此,dp[i][j] 应该是上述三种操作的最小值。
    初始化:
  • dp[0][j] 表示将空字符串转换为 word2 的前 j 个字符所需的操作数,即插入 j 个字符,所以 dp[0][j] = j
  • dp[i][0] 表示将 word1 的前 i 个字符转换为空字符串所需的操作数,即删除 i 个字符,所以 dp[i][0] = i

代码

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(); i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i <= word2.length(); i++) {
            dp[0][i] = i;
        }
        for (int i = 1; i <= word1.length(); i++) {
            for (int j = 1; j <= word2.length(); 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[word1.length()][word2.length()];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值