题目描述:
给你两个单词 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(); } };