问题
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
示例:
输入:word1 = “horse”, word2 = “ros”
输出:3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
思路
动态规划问题,具有独立的子问题,设dp[i][j]
为s1[0..i]
和s2[0..j]
的最小编辑距离,则
状态转移方程为:
即对s1[0..i]
和s2[0..j]
的最后一个字符,可以做三种操作使之相同,距离分别加1,但当s1[i] == s2[j] 时,替换操作可以不需要,不用加1,然后三种操作取编辑距离最小的一个。
基本情况是当一个字符串为空时,编辑距离等于另一个字符串的长度。
代码
pub fn min_distance(word1: String, word2: String) -> i32 {
let mut dp = vec![vec![0;word2.len() + 1];word1.len() + 1];
let s1 = word1.as_bytes();
let s2 = word2.as_bytes();
// base case
for i in 1..=word1.len() {
dp[i][0] = i as i32;
}
for i in 1..=word2.len() {
dp[0][i] = i as i32;
}
for i in 1..=word1.len() {
for j in 1..=word2.len() {
if s1[i-1] == s2[j-1] {
// 字符相等可以什么也不做,或者插入和删除
dp[i][j] = dp[i-1][j-1];
} else {
// 字符不等可以替换,插入和删除
dp[i][j] = dp[i-1][j-1] + 1;
}
// 删除和插入操作,对应4种情况
dp[i][j] = min(dp[i][j], dp[i-1][j] + 1);
dp[i][j] = min(dp[i][j], dp[i][j-1] + 1);
}
}
dp[word1.len()][word2.len()]
}