跳转至

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

力扣链接(中等):https://leetcode.cn/problems/delete-operation-for-two-strings

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

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

示例 1:

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

示例 2:

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

提示:

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

个人题解

方法一

  • dp[i][j] 表示 word1word2 中区间分别为 [0, i - 1][0, j - 1] 的子串相等所需删除的最小次数;

  • 初始化 dpdp[i][0] 代表 word2 长度为 0 时,word1 至少要删除多少次才能和 word2 相等;dp[0][j] 同理;

  • 状态转移:如果当前项相等,那么在 dp[i - 1][j - 1] 基础上,不用删除任何项,即 dp[i][j] = dp[i - 1][j - 1];如果当前项不相等,则有三种情况:

    • 删除 word1 中的当前项:在 word1[0, i - 2]word2[0, j - 1] 子串相等所需删除次数的基础上,再删除一次,即 dp[i][i] = dp[i - 1][j] + 1
    • 删除 word2 中的当前项:在 word1[0, i - 1]word2[0, j - 2] 子串相等所需删除次数的基础上,再删除一次,即 dp[i][i] = dp[i][j - 1] + 1
    • 分别对 word1word2 删除当前项:在 word1[0, i - 2]word2[0, j - 2] 子串相等所需删除次数的基础上,再删除两次,即 dp[i][i] = dp[i - 1][j - 1] + 2

    取上面三种情况的最小值作为 dp[i][j] 即可。

C++
class Solution {
public:
    int minDistance(string word1, string word2) {
        const int N = 510;
        int dp[N][N] = {};

        // word2 长度为 0,word1 子串 [0, i - 1] 要删除多少次
        for(int i = 0; i <= word1.size(); i++) dp[i][0] = i;
        // word1 长度为 0,word2 中子串 [0, j - 1] 要删除多少次
        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++) {
                // 如果当前项相等,那么在 dp[i - 1][j - 1] 基础上,不用删除任何项
                if(word1[i - 1] == word2[j - 1]) dp[i][j] = dp[i - 1][j - 1];
                // 如果不相等,有三种情况,删 word1/word2/两个都删
                else dp[i][j] = min({dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + 2});
            }
        }

        return dp[word1.size()][word2.size()];
    }
};

方法二

转换为最长公共子序列的逻辑求解:1035/1143. 不相交的线/最长公共子序列

要使得两个字符串相等,那么就是找两个子串的公共部分,最后,用两个串的总长度减去求得的最长公共子序列的长度即可。