给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
---插入一个字符
---删除一个字符
---替换一个字符
- 确定是最值问题,解题过程可枚举,考虑动态规划
- 最后一步:假定经过最少的操作次数我们把word1转换成了word2,假定最后一步之前的单词为wordX
- 如果wordX比word2短一个字符,则word2必然是wordX增加一个字符得到的;
- 如果wordX比word2长一个字符,则word2必然是wordX删除一个字符得到的;
- 如果wordX和wordX一样长,则word2要么就是wordX,要么就是wordX替换一个字符得到的。
- 确定状态数组dp[i][j]为word1转化为word2的最小操作数,其中i为word1的长度,j为word2的长度
- 确定状态转移方程:
- 最后一步是增加一个字符:dp[i][j] = dp[i-1][j]+1
- 最后一步是删除一个字符:dp[i][j] = dp[i+1][j]+1
- 最后一步是替换一个字符:dp[i][j] = dp[i-1][j-1]+1
- 确定边界:word1为空串s[0][j] = j;word2为空串s[i][0] = i;
- 确定初值:最坏情况下,word1,word2没有一个相同字符,则需要替换掉较短字符串,再把剩下的字符加入或删除。因此操作次数为两个字符串长度的大者。
class Solution {
public:
int minDistance(string word1, string word2) {
int src_len = word1.length();
int dst_len = word2.length();
// 边缘场景
if (src_len == 0 || dst_len == 0) {
return src_len == 0 ? dst_len : src_len;
}
// DP数组
vector<vector<int>> min_instance(src_len + 1, vector<int>(dst_len + 1));
// 边界条件:空串
for (int i = 0; i < src_len + 1; i++) {
min_instance[i][0] = i;
}
for (int j = 0; j < dst_len + 1; j++) {
min_instance[0][j] = j;
}
// DP => 最后一步
for (int i = 1; i < src_len + 1; i++) {
for (int j = 1; j < dst_len + 1; j++) {
int min_add = min_instance[i - 1][j] + 1;
int min_erase = min_instance[i][j - 1] + 1;
int min_replace = min_instance[i - 1][j - 1];
if (word1[i - 1] != word2[j - 1])
min_replace += 1;
min_instance[i][j] = min(min_add, min(min_erase, min_replace));
}
}
return min_instance[src_len][dst_len];
}
};