编辑距离
给你两个单词 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。分析思路如下:
假设有词A和词B,想要把A转换成B(与把B转换成A等价),且只能运用增、删、换三种方法操作单个词,因此总共可以归纳为三种操作方法:
- 在A中增加一个字母(与在B中删掉一个字母等价)
- 在A中删掉一个字母(与在B中增加一个字母等价)
- 在A中替换一个字母(与在B中替换一个字母等价)
现在视线回到A和B:
- A的最后一个字母(A[i])与B的最后一个字母(B[j])是相等的,那么将A转换为B就和把A[0…i-1]转换为B[0…j-1]是等价的。
- 若不相等,我们可以对A进行上述三种操作:
- ① 在A的末尾增加一个字母,使之等于B[j],这样的话,将现在的A转换为B就和把A[0…i]转换为B[0…j-1]是等价的。
- ② 在B的末尾增加一个字母,使之等于A[i],这样的话,将现在的A转换为B就和把A[0…i-1]转换为B[0…j]是等价的。
- ③ 将A[i]替换为B[j],这样的话,将现在的A转换为B就和把A[0…i-1]转换为B[0…j-1]是等价的。
因为上述三种情况都是和操作后的A、B等价,因此都要操作数都要+1
模式匹配:对于当前的问题,我们可以通过求解它的子问题来获得答案。这种情况下,一般使用自顶而下的递归或者自底向上的动态规划。众所周知递归耗费空间以及修枝很麻烦,因此一般还是DP。
上代码:
class Solution {
public:
int minDistance(string word1, string word2) {
int len1 = word1.size(), len2 = word2.size();
vector<vector<int>> dp(len1+1, vector<int>(len2+1));
//初始化
for (int i = 0; i <= len2; i++)
{
dp[0][i] = i;
}
for (int i = 0; i <= len1; i++)
{
dp[i][0] = i;
}
//自底向上DP
for (int i = 1; i <= len1; i++)
{
for (int j = 1; j <= len2; 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],min(dp[i][j-1],dp[i-1][j-1])) + 1;
}
}
}
return dp[len1][len2];
}
};
问题解决,这个算法要记住!!!