代码随想录算法训练营第56天 |583. 两个字符串的删除操作、72. 编辑距离

TFTree 发布于 2023-08-19 2527 次阅读


583. 两个字符串的删除操作 - 力扣(Leetcode)

思路:

  • 使用动态规划

    1. 确定dp数组以及下标的含义

      • dp[i][j]的定义为:以word1[i]为结尾和以word2[j]为结尾的字符串最大相同连续子序列的长度
    2. 确定递推公式

      // 状态转移方程
      // 相等的时候就只要将长度加一
      if(word1[i -1 ] == word2[j - 1]) {
      dp[i][j] = dp[i - 1][j - 1] + 1;
      }
      else {
      // 不相等的时候要考虑删去word1[i - 1]的情况和删去word2[j - 1]的情况
      dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
      }
    3. dp数组如何初始化

      vector< vector<int> > dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
    4. 确定遍历顺序

      从 i = 1 和 j = 1 开始从前往后遍历

我的AC代码

// 时间复杂度O(n x m),空间复杂度O(n x m)
class Solution {
public:
int minDistance(string word1, string word2) {
vector< vector<int> > dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
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] + 1;
}
else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return (word1.size() + word2.size() - 2 * dp[word1.size()][word2.size()]);
}
};

标准答案

直接考虑删除次数

// 时间复杂度O(n x m),空间复杂度O(n x m)
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size() + 1, vector<int>(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()];
}
};

考虑最长公共子序列

// 时间复杂度O(n x m),空间复杂度O(n x m)
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1, 0));
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] + 1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return word1.size()+word2.size()-dp[word1.size()][word2.size()]*2;
}
};

72. 编辑距离 - 力扣(LeetCode)

思路:

  • 使用动态规划

    1. 确定dp数组以及下标的含义

      • dp[i][j]的定义为:以i -1为结尾和以j - 1为结尾的字符串需要编辑距离的次数
    2. 确定递推公式

      // 状态转移方程
      // 分两种情况
      // 第一种情况,两个字符相等,那么不需要编辑
      // 即dp[i][j] = dp[i - 1][j - 1];
      // 第二种情况
      // 两个字符不相等,那么就有三种操作,取其中的最小值
      // 让word1删字符,dp[i - 1][j] + 1
      // 让word2删字符,dp[i][j - 1] + 1
      // 替换字符,dp[i - 1][j - 1] + 1
      if(word1[i - 1] == word2[j - 1]) {
      dp[i][j] = dp[i - 1][j - 1];
      }
      else {
      dp[i][j] = min(min(dp[i][j - 1] + 1, dp[i - 1][j] + 1), dp[i - 1][j - 1] + 1);
      }
    3. dp数组如何初始化

      for(int i = 1; i <= word1.size(); ++i) {
      dp[i][0] = i;
      }
      for(int i = 1; i <= word2.size(); ++i) {
      dp[0][i] = i;
      }
    4. 确定遍历顺序

      // 从前往后

我的AC代码

// 时间复杂度O(n*m),空间复杂度O(n*m)
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
for(int i = 1; i <= word1.size(); ++i) {
dp[i][0] = i;
}
for(int i = 1; i <= word2.size(); ++i) {
dp[0][i] = i;
}
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(min(dp[i][j - 1] + 1, dp[i - 1][j] + 1), dp[i - 1][j - 1] + 1);
}
}
}
return dp[word1.size()][word2.size()];
}
};

标准答案

// 时间复杂度O(n*m),空间复杂度O(n*m)
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
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 - 1][j], dp[i][j - 1]}) + 1;
}
}
}
return dp[word1.size()][word2.size()];
}
};