算法day39-动态规划(12)

目录

  1. 不同的子序列
  2. 两个字符串的删除操作
  3. 编辑距离

一、不同的子序列

 https://leetcode.cn/problems/distinct-subsequences/?envType=problem-list-v2&envId=8At1GmaZ

 

class Solution {
    public int numDistinct(String s, String t) {
        //d[i][j]:以i-1结尾的s子序列中有以j-1结尾的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)){
                    //使用s.charAt(i-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()];
    }
}

 

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

 https://leetcode.cn/problems/delete-operation-for-two-strings/?envType=problem-list-v2&envId=8At1GmaZ

 

class Solution {
    public int minDistance(String word1, String word2) {
        //dp[i][j]:以i-1结尾的word1和以j-1结尾的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, dp[i][j-1]+1);
                }
            }
        }
        return dp[word1.length()][word2.length()];

    }
}

 

三、编辑距离

 https://leetcode.cn/problems/edit-distance/description/?envType=problem-list-v2&envId=8At1GmaZ

 

1. 定义状态

定义一个二维数组 dp,其中 dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需的最小操作数。

2. 初始化

  • dp[0][j] = j:表示将空字符串转换为 word2 的前 j 个字符需要插入 j 个字符。

  • dp[i][0] = i:表示将 word1 的前 i 个字符转换为空字符串需要删除 i 个字符。

3. 状态转移

对于 dp[i][j]

  • 如果 word1.charAt(i-1) == word2.charAt(j-1),说明 word1[i-1]word2[j-1] 相同,不需要进行任何操作,此时 dp[i][j] = dp[i-1][j-1]

  • 如果 word1.charAt(i-1) != word2.charAt(j-1),我们需要选择以下三个操作中的最小代价:

    • 删除字符:dp[i-1][j] + 1,即从 word1 删除一个字符,保持 word2 不变。

    • 插入字符:dp[i][j-1] + 1,即向 word1 中插入一个字符,使其与 word2 匹配。

    • 替换字符:dp[i-1][j-1] + 1,即将 word1[i-1] 替换为 word2[j-1]

4. 返回结果

最后,dp[word1.length()][word2.length()] 即为将整个 word1 转换为 word2 的最小编辑距离。

时间复杂度

  • 时间复杂度:O(m * n),其中 mn 分别是 word1word2 的长度。我们需要遍历二维数组 dp,每个元素的填充操作是常数时间。

  • 空间复杂度:O(m * n),需要 O(m * n) 的空间来存储 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(Math.min(dp[i-1][j]+1, dp[i][j-1]+1), dp[i-1][j-1]+1);
                }
            }
        }
        return dp[word1.length()][word2.length()];
    }
}

 

posted @ 2025-06-10 22:00  筱倩  阅读(20)  评论(0)    收藏  举报