算法Day56 | 583. 两个字符串的删除操作, 72. 编辑距离,序列总结

文章介绍了如何使用动态规划解决583题和72题,这两个问题都涉及到字符串的编辑距离和删除操作。通过构建二维dp数组,根据字符是否相同来确定操作步骤,如替换、删除或添加。对于583题,可以通过最长公共子序列来优化;72题则要考虑三种操作:替换、删除和添加。初始化dp数组通常从最长边开始,最终返回dp数组的最后一个元素表示最小操作步数。
摘要由CSDN通过智能技术生成

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

题目链接:583. 两个字符串的删除操作
dp数组 : 以i - 1为结尾的word1和以j - 1为结尾的word2相同的最少操作为dp[i][j]

递推公式

dp[i][j] = (word1[i - 1] == word2[j - 1])
					? dp[i - 1][j - 1]
					: max(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

dp[i - 1][j - 1]

  • dp[i - 1][j - 1] 相当于word1删除了第i - 1个元素,word2删除了第j - 1个元素。因为word1[i - 1]word2[j - 1]是一样的,所以删除后步骤不变

max(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

  • 因为是不一样的,所以删除步骤取两个dp[i - 1][j] dp[i][j - 1]中最大的

初始化
二维数组初始化第一行和第一列。
dp[i][0] = i dp[0][j] = j

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() + 1; ++i) dp[i][0] = i;
        for (int j = 0; j < word2.size() + 1; ++j) dp[0][j] = j;
        for (int i = 1; i < word1.size() + 1; ++i) {
            for (int j = 1; j < word2.size() + 1; ++j) {
                dp[i][j] = (word1[i - 1] == word2[j - 1])
                        	? dp[i - 1][j - 1]
                        	: min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
            }
        }
        return dp.back().back();
    }
};

可以用1143.最长公共子序列 的思路来算,word1word2的公共求出,结果一相减也就求出。

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() + 1; ++i) {
            for (int j = 1; j < word2.size() + 1; ++j) {
                dp[i][j] = (word1[i - 1] == word2[j - 1])
                           ? dp[i - 1][j - 1] + 1
                           : max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        return word1.size() + word2.size() - 2 * dp.back().back();
    }
};

72. 编辑距离

题目链接:72. 编辑距离
如果word1转化到word2需要删除字母,相当于word2转换到word1添加字母
换而言之,长的单词转化为短的单词,只需要 删除替换 操作即可。

dp数组 : 以i - 1为结尾的word1和以j - 1为结尾的word2相同的最少操作为dp[i][j]

递推公式

dp[i][j] = (word1[i - 1] == word2[j - 1])
					? dp[i - 1][j - 1]
					: min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;

dp[i - 1][j - 1]

  • dp[i - 1][j - 1] 因为是一样的,所以操作步骤不变

min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;

  • 单词长度不同选择删除
    dp[i - 1][j]相当于 word1删除了第i - 1个字母
    dp[i][j - 1]相当于 word2删除了第j - 1个字母

  • 单词长度相同选择替换
    dp[i - 1][j - 1]相当于word1中的第i - 1个字母和word2中的第j - 1个字母不同,进行替换

初始化
二维数组初始化第一行和第一列。
由于单词长度不同,因此选择删除操作进行初始化:dp[i][0] = i dp[0][j] = j

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() + 1; ++i) dp[i][0] = i;
        for (int j = 0; j < word2.size() + 1; ++j) dp[0][j] = j;
        for (int i = 1; i < word1.size() + 1; ++i) {
            for (int j = 1; j < word2.size() + 1; ++j) {
                dp[i][j] = (word1[i - 1] == word2[j - 1])
                           		? dp[i - 1][j - 1]
                           		: min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;
            }
        }
        return dp.back().back();
    }
};

序列总结

首先,数组dp[i][j]要设置为从 i - 1 j - 1的表述方式,是为了初始化简单;其次,根据题意来比较,来对递推公式的细节分支的计算;最后就是为了服务于dp数组进行初始化,遍历顺序。

基本上所有的二维dp数组都可以压缩到一维,但是可能会造成代码的可读性太差。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值