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

题目来源

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

题目描述

leetcode:583. 两个字符串的删除操作_第1张图片

题目解析

分析

  • 给定两个字符串s1和s2,分别删除若干字符之后使得两个字符串相同,则剩下的字符为两个字符串的公共子序列。
  • 为了使得删除操作的次数最少,剩下的字符应该尽可能的多
  • 当剩下的字符为两个字符串的最长公共子序列时,删除操作的次数最少
  • 我们只要求出了最长公共子序列的长度,拿两个字符串的长度之和减去2倍的最长公共子序列的长度就可以了。

思路:最长公共子串

  • dp[i][j]:
    • str1的前i个字符和str2的前j个字符组成的两个单词的最长公共子序列的长度
    • 最终结果是dp[N1][N2]
  • 状态转移方程:
    • 如果当前字符相等,那么dp[i][j] = dp[i - 1][j - 1] + 1
      • 因为最长相同子序列又多了一个相同的字符,所以长度加以
      • 因为dp数组的大小为(N1 + 1) * (N2 + 1),所以比较的是str1[i - 1]与str2[j - 1]
      • (如果str1[i - 1] == str2[j - 1],那么这个字符一定在lcs中。否则,str1[i - 1]和str2[j - 1]这两个字符至少有一个不在lcs中,需要丢弃一个。)
    • 如果当前字符不相等,那么就错位比,分别从str1和str2中去掉一个字符,也就是比较dp[i - 1][j]与dp[i][j - 1]之间的关系(谁能让 lcs 最长,就听谁的),即dp[i][j] = std::max(dp[i - 1][j], dp[i][j - 1]);
class Solution {
public:
    int minDistance(string word1, string word2) {
        int n1 = word1.size(), n2 = word2.size();
        vector<vector<int>> dp(n1 + 1, vector<int>(n2 + 1, 0));
        for (int i = 1; i <= n1; ++i) {
            for (int j = 1; j <= n2; ++j) {
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return n1 + n2 - 2 * dp[n1][n2];
    }
};

思路:编辑距离

  • 其实 word2 删除一个字符,和跟在 word1 对应的地方加上那个要删除的字符,达到的效果是一样的,并不影响最终的步骤数
  • 和leetcode:72. 编辑距离,它没有替换操作而已
class Solution {
public:
    int minDistance(string word1, string word2) {
        int n1 = word1.size(), n2 = word2.size();
        vector<vector<int>> dp(n1 + 1, vector<int>(n2 + 1, 0));
        for (int i = 0; i <= n1; ++i) dp[i][0] = i; // 如果word2是空串,自然word1有多少删多少。
        for (int j = 0; j <= n2; ++j) dp[0][j] = j; // 如果word1是空串,自然word2有多少删多少。
        for (int i = 1; i <= n1; ++i) {
            for (int j = 1; j <= n2; ++j) {
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];  // 如果最尾的字符相同,那就无须操作,只看前段的结果
                } else {// 如果最尾的字符不同,那注定要删一个,就看删谁,抉择的基准是从中挑一个最省的,再+1个删除操作。
                    dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[n1][n2];
    }
};

类似题目

题目 思路
leetcode:1143. 最长公共子序列 Longest Increasing Subsequence 只关心str1[0…i],str2[0…j],对于它们的最长公共子序列长度是多少(样本对应模型,往往以考虑结尾来组织可能性)
leetcode:583. 使得两个字符相同的最少删除次数 Delete Operation for Two Strings
leetcode:712. 使得两个字符相同时所需删除字符最小ASCII值和 Minimum ASCII Delete Sum for Two Strings
leetcode:72. 编辑距离 Edit Distance 编辑距离有个替换操作,这是它与最长公共子序列最大的不同

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