携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
题目描述
给定两个单词word1、word2,长度分别为m、n。返回将word1转换为word2所需要的最小操作次数。可以使用的操作有:删除当前字符、替换当前字符、在当前字符后插入一个字符
例1:输入:"word1:"abcdaaa" word2:"aabcaaa"" 输出:"2"
解释:将输入的word1变为word2的操作方法有很多,比如在第一个word1[0]后分别插入abc,word1变为"aabcbcdaaa",然后删除word1的4、5、6位置的字符即可,这样操作的次数即为6次。此外,也可在word[0]后插入a,word1变为"aabcdaaa",然后将位置5的d删除,即可达到word2,这样操作的次数为2。在所有的变换方法中最少的操作次数即为2。
本题值得注意的地方
- word1、word2均由小写字母组成。
- word1与word2的长度m、n不一定是相同的。
原题地址:72. 编辑距离
解题思路
当我们对word1的某一个字符进行变换操作时,可以选择的操作其实有四种:增加、删除、替换、不做任何操作。word2可以由word1做无数种种操作得到。
这里定义 dp[i][j] 表示由 word1 的前 i 个字符得到 word2 的前 j 个字符所需要的最小操作数。则总结起来dp[i][j]可以由以下几种情形得到:
- 由dp[i-1][j]得到,dp[i-1][j]word1 的前 i-1 个字符得到 word2 的前 j 个字符所需要的最小操作数。即删除 word1[i]位置的字符。该情形可以得到状态转移方程为:。
- 由dp[i][j-1],即在word1 的位置 i 后插入 字符word2[j]。该情形可以得到状态转移方程为:。
- 由dp[i-1][j-1],即将word1 i 位置的字符替换为 word2 j 位置的字符。但当word1[i]和word[j]相同时,就不必替换了。该情形可以得到状态转移方程为:。
我们所求的答案就是dp[m][n]。
实现代码
class Solution {
public:
int minDistance(string word1, string word2) {
// 用来存储各种变化策略所需要的最小操作数
vector<vector<int>> dp(word1.size()+1,vector<int>(word2.size()+1,0x3f3f3f3f));
// 初始化用word1 的前0个字符得到word2的前i个字符,其所需最小操作就是添加字符的次数i次
for(int i = 1;i <= word2.size();i++) dp[0][i] = i;
// 初始化用word1 的前i个字符得到word2的前0个字符,其所需最小操作就是删除字符的次数i次
for(int i = 1;i <= word1.size();i++) dp[i][0] = i;
// "" -> "" 需要零次操作
dp[0][0] = 0;
// 依次计算从word1的前1、2、3·····m个字符得到word2的前1、2、3······n个字符所需要的操作次数
for(int i = 1;i <= word1.size();i++){
for(int j = 1;j <= word2.size();j++){
// 计算word1的前i个字符转换为word2前j个字符所需要的最小操作次数
dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1;
if(word1[i-1] == word2[j-1]) dp[i][j] = min(dp[i][j],dp[i-1][j-1]);
else dp[i][j] = min(dp[i][j],dp[i-1][j-1]+1);
}
}
// 返回word1 -> word2 的最小操作次数
return dp[word1.size()][word2.size()];
}
};