力扣第583题 两个字符串的删除操作 c++ 动态规划 附Java代码

题目

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

中等

相关标签

字符串   动态规划

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

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

示例 1:

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

示例  2:

输入:word1 = "leetcode", word2 = "etco"
输出:4

提示:

  • 1 <= word1.length, word2.length <= 500
  • word1 和 word2 只包含小写英文字母

思路和解题方法

  • minDistance 函数用于计算两个字符串 word1 和 word2 之间的最小编辑距离。
  • 创建一个二维向量 dp 作为状态转移表,它的大小为 word1.size()+1 行和 word2.size()+1 列。
  • 初始化状态转移表的第一行和第一列,表示将一个字符串转换为空串所需的操作次数。
  • 使用嵌套的循环遍历状态转移表的剩余部分。
  • 如果 word1 的第 i-1 个字符和 word2 的第 j-1 个字符相等,则当前位置的编辑距离与前一个位置相同,即 dp[i][j] = dp[i-1][j-1]
  • 如果 word1 的第 i-1 个字符和 word2 的第 j-1 个字符不相等,则当前位置的编辑距离为左边和上方两个位置中的最小值加一,即 dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1)
  • 最后返回状态转移表右下角的值,即最终的最小编辑距离。

复杂度

        时间复杂度:

                O(mn)

        时间复杂度为O(mn),其中m和n分别为word1和word2的长度。这是因为该算法需要填充一个m行n列的状态转移表,每个格子需要进行常数级别的操作,因此总时间复杂度为O(mn)。

        空间复杂度

                O(mn)

        空间复杂度也是O(mn),因为该算法需要创建一个m+1行n+1列的二维向量dp来保存状态转移表。每个格子都需要保存一个整数值,因此占用的空间为O(mn)。

c++ 代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        // 创建一个二维向量dp,用于存储状态转移表
        vector> dp(word1.size()+1, vector(word2.size()+1));

        // 初始化状态转移表的第一行和第一列
        for(int i = 0; i <= word1.size(); i++)
            dp[i][0] = i;
        for(int j = 0; j <= word2.size(); j++)
            dp[0][j] = j;

        // 填充状态转移表
        for(int i = 1; i <= word1.size(); i++) {
            for(int j = 1; j <= word2.size(); j++) {
                if(word1[i-1] == word2[j-1]) {
                    // 如果当前字符相等,则当前位置的编辑距离与前一个位置相同
                    dp[i][j] = dp[i-1][j-1];
                }
                else {
                    // 如果当前字符不相等,则当前位置的编辑距离为左边和上方两个位置中的最小值加一
                    dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1);
                }
            }
        }

        // 返回状态转移表右下角的值,即最终的编辑距离
        return dp[word1.size()][word2.size()];
    }
};

附另一种C++代码

  • 代码中使用动态规划的思想,通过构建一个二维的状态转移表 dp 来保存子问题的最优解。其中,dp[i][j] 表示 word1 的前 i 个字符和 word2 的前 j 个字符的最长公共子序列长度。
  • 首先,初始化状态转移表的第一行和第一列,它们都是零,表示一个空串与任意字符串的LCS长度都为零。
  • 然后,从左上角开始逐行逐列填充状态转移表。如果当前字符相等,则当前位置的LCS长度为左上角格子的值加一;如果当前字符不相等,则当前位置的LCS长度为左边和上方两个格子中的最大值。
  • 最后,返回将两个字符串变成相同序列所需删除字符的最少次数,即两个字符串的长度之和减去LCS长度的两倍。
class Solution {
public:
    int minDistance(string word1, string word2) {
        // 创建一个二维向量dp,用于保存子问题的最优解
        vector> dp(word1.size()+1, vector(word2.size()+1, 0));

        // 使用嵌套循环遍历状态转移表dp
        for (int i=1; i<=word1.size(); i++){
            for (int j=1; j<=word2.size(); j++){
                if (word1[i-1] == word2[j-1]) {
                    // 如果当前字符相同,则当前位置的LCS长度为左上角格子的值加一
                    dp[i][j] = dp[i-1][j-1] + 1;
                }
                else {
                    // 如果当前字符不同,则当前位置的LCS长度为左边和上方两个格子中的最大值
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }

        // 返回word1和word2的长度之和减去LCS长度的两倍
        return word1.size() + word2.size() - dp[word1.size()][word2.size()] * 2;
    }
};

Java代码

1

  • 创建一个二维数组dp,大小为len1 + 1行和len2 + 1列,其中len1len2分别是word1word2的长度。
  • 初始化dp数组的第一行和第一列,表示将一个字符串转换为空串所需的操作次数。
  • 使用嵌套的循环遍历dp数组的剩余部分。
  • 如果word1的第i-1个字符和word2的第j-1个字符相等,则当前位置的最长公共子序列长度为左上方对角线的值加一,即dp[i][j] = dp[i - 1][j - 1] + 1
  • 如果word1的第i-1个字符和word2的第j-1个字符不相等,则当前位置的最长公共子序列长度为左边和上方两个位置中的较大值,即dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
  • 最后返回len1 + len2 - dp[len1][len2] * 2,即将word1word2的总长度减去最长公共子序列的长度的两倍。
class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        int[][] dp = new int[len1 + 1][len2 + 1];

        // 初始化状态转移表的第一行和第一列,它们都是零,表示一个空串与任意字符串的LCS长度都为零。
        for (int i = 0; i <= len1; i++) {
            dp[i][0] = 0;
        }
        for (int j = 0; j <= len2; j++) {
            dp[0][j] = 0;
        }

        // 使用嵌套循环遍历状态转移表dp
        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    // 如果当前字符相同,则当前位置的LCS长度为左上角格子的值加一
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    // 如果当前字符不同,则当前位置的LCS长度为左边和上方两个格子中的最大值
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // 返回word1和word2的长度之和减去LCS长度的两倍
        return len1 + len2 - dp[len1][len2] * 2;
    }
}

2.

  • 创建一个二维数组dp,大小为word1.length() + 1行和word2.length() + 1列。
  • 初始化dp数组的第一行和第一列,表示将一个字符串转换为空串所需的删除字符操作次数。
  • 使用嵌套的循环遍历dp数组的剩余部分。
  • 如果word1的第i-1个字符和word2的第j-1个字符相等,则当前位置的删除字符个数与左上方对角线的值相同,即dp[i][j] = dp[i - 1][j - 1]
  • 如果word1的第i-1个字符和word2的第j-1个字符不相等,则当前位置的删除字符个数为左上方对角线的值加2(替换操作),或者左边和上方两个位置中的较小值加1(删除操作),即dp[i][j] = Math.min(dp[i - 1][j - 1] + 2, Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1))
  • 最后返回dp[word1.length()][word2.length()],即最终的最小删除字符个数。
class Solution {
    public int minDistance(String word1, String word2) {
        // 创建一个二维数组dp,用于保存子问题的最优解
        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;
        }
        
        // 使用嵌套循环遍历状态转移表dp
        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, // 替换操作,编辑距离+2
                                        Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)); // 删除或插入操作,编辑距离+1
                }
            }
        }
        
        // 返回word1和word2的长度之和减去编辑距离
        return dp[word1.length()][word2.length()];
    }
}

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

你可能感兴趣的:(leetcode,动态规划,数据结构,leetcode,c++,java,动态规划,算法)