题目描述:
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
题目解答:
class Solution {
public:int minDistance(string word1, string word2) {int m = word1.size(), n = word2.size();vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));for (int i = 0; i <= m; ++i) {for (int j = 0; j <= n; ++j) {if (i == 0 || j == 0)i == 0 ? dp[i % 2][j] = j : dp[i % 2][j] = i;else {dp[i % 2][j] =min(dp[(i - 1) % 2][j - 1],min(dp[(i - 1) % 2][j], dp[i % 2][j - 1])) +1;if (word1[i - 1] == word2[j - 1])dp[i % 2][j] =min(dp[i % 2][j], dp[(i - 1) % 2][j - 1]);}}}return dp[m % 2][n];}
};
题目思路:
为计算两个字符串之间的编辑距离(Levenshtein距离),使用动态规划的思想。
-
初始化数组:
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
初始化一个大小为
(m+1) × (n+1)
的二维数组dp
,其中dp[i][j]
表示将word1
的前i
个字符转换为word2
的前j
个字符所需的最小编辑距离。 -
填充数组:
for (int i = 0; i <= m; ++i) {for (int j = 0; j <= n; ++j) {
双重循环遍历
word1
和word2
的所有可能的前缀子串。 -
处理第一行和第一列:
if (i == 0 || j == 0)i == 0 ? dp[i % 2][j] = j : dp[i % 2][j] = i;
当其中一个字符串为空时,编辑距离就是另一个字符串的长度。这里使用了条件表达式,如果
i
为0,那么dp[i % 2][j]
就被赋值为j
,否则被赋值为i
。 -
处理其他情况:
else {dp[i % 2][j] = min(dp[(i - 1) % 2][j - 1], min(dp[(i - 1) % 2][j], dp[i % 2][j - 1])) + 1;if (word1[i - 1] == word2[j - 1])dp[i % 2][j] = min(dp[i % 2][j], dp[(i - 1) % 2][j - 1]); }
对于非第一行和第一列的位置,计算编辑距离并填充
dp
数组。如果当前字符相同,则直接继承前一步的编辑距离,否则在前一步的基础上进行插入、删除或替换操作,选择最小的编辑距离。 -
最终结果:
return dp[m % 2][n];
返回
dp[m % 2][n]
,表示将word1
的前m
个字符转换为word2
的前n
个字符所需的最小编辑距离。
这段代码的时间复杂度为O(m * n),空间复杂度为O(min(m, n)),因为滚动数组优化仅保留了两行的状态。