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

Day56

    • 583. 两个字符串的删除操作
    • 72. 编辑距离
    • 序列总结

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数组都可以压缩到一维,但是可能会造成代码的可读性太差。

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