题目大意
编辑距离,经典动态规划题目。给出针对字符串的三种操作,替换,删除和插入,编辑距离d
,表示将字符串a
使用上述三种操作转换为b
所需要的步骤。
思路
计算字符串a
和b
之间的编辑距离d
。
-
子问题构造:
a
的前缀子串和b
的前缀子串之间的编辑距离,前缀子串即包含某位置前的所有字符的子串。因为计算a
的前缀子串与b
的编辑距离时需要考虑b
中的所有字符,因此a
和b
的子串都要考虑。 -
递推公式: 递推式需要考虑
a[i]
和b[j]
是否相同的情况,例如对于hoe
和rose
,因为两者最后的字符相同,因此dis(ho, ros) == dis(hoe, rose)
的距离。a[i] == b[j] dp[i][j] = min( dp[i - 1][j - 1], // no need replace dp[i - 1][j] + 1, // delete a[i] dp[i][j - 1] + 1 // insert b[j] ) a[i] == b[j] dp[i][j] = min( dp[i - 1][j - 1] + 1, // replace dp[i - 1][j] + 1, // delete a[i] dp[i][j - 1] + 1 // insert b[j] )
实际上若a[i]==b[j]
,那么可以肯定dp[i][j]=dp[i-1][j-1]
。对了,不要忘了初始化。
代码
typedef vector<vector<int>> vvi;
class Solution {
public:
int minDistance(string word1, string word2) {
const int asz = word1.size(), bsz = word2.size();
if (asz == 0 || bsz == 0)
return asz + bsz;
vvi dp(asz + 1);
for (size_t i = 0; i <= asz; i++) {
dp[i].resize(bsz + 1, max(asz, bsz));
dp[i][0] = i;
}
for (size_t i = 0; i <= bsz; i++)
dp[0][i] = i;
for (size_t dpi = 1; dpi <= asz; dpi++) {
for (size_t dpj = 1; dpj <= bsz; dpj++) {
size_t i = dpi - 1, j = dpj - 1;
if (word1[i] == word2[j]) dp[dpi][dpj] = min({
dp[dpi][dpj], dp[dpi - 1][dpj - 1],
dp[dpi - 1][dpj] + 1, dp[dpi][dpj - 1] + 1
});
else dp[dpi][dpj] = min({
dp[dpi][dpj], dp[dpi - 1][dpj - 1] + 1,
dp[dpi - 1][dpj] + 1, dp[dpi][dpj - 1] + 1
});
}
}
return dp[asz][bsz];
}
};
总结
经典题目