72. 编辑距离(Edit Distance)

题目描述:

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符
 

示例 1:

输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:

输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

解题思路:

  这道题是一道典型的动态规划题目,有一句话不是说字符串相关的题目百分之八十都是动态规划吗(~-~)

  因为有两个字符串,所以dp数组要使用二维数组,dp[i][j]表示以word1[i],word2[j]结束的子串需要做的最少操作数。因为可以想到,当word1[i]等于word2[j],不需要做任何操作,所以dp[i][j]等于dp[i-1][j-1];当word1[i]不等于word2[j]时,三种方法都可以应对当前的局面,假设把word2变成word1,即所有操作都在word2上执行:

  当插入一个字符时,可以假设在word2[j]之后插入了word1[i],这时word1[i]就已经不用考虑了,只用考虑word2[j]结束的子串和word1[i-1]结束的子串。因此这时需要的操作数等于dp[i-1][j] + 1。

  当删除一个字符时,可以假设直接删除word2[j],这时只用考虑word2[j-1]结束的子串和word1[i]结束的子串。因此这时需要的操作数等于dp[i][j-1] + 1。

  当替换一个字符时,可以假设把word2[j],替换为了word1[i],这时只用考虑word2[j-1]结束的子串和word1[i-1]结束的子串。因此这时需要的操作数等于dp[i-1][j-1] + 1。

  选择哪个操作取决于哪个操作的值最小,因此只需要令dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1即可。注意构造dp数组时在设置好边界,边界从word1或word2为空串时开始。

  代码如下:

class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp{word1.size() + 1, vector<int>(word2.size() + 1)};
        for (int i = 1; i != word2.size() + 1; ++i)
            dp[0][i] = i;
        for (int i = 1; i != word1.size() + 1; ++i)
            dp[i][0] = i;
        
        for (int i = 1; i != word1.size() + 1; ++i)
            for (int j = 1; j != word2.size() + 1; ++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], dp[i-1][j]}) + 1;
                }
            }
            
        return dp.back().back();
    }
};
原文地址:https://www.cnblogs.com/yxsrt/p/13236149.html