leetcode-72-Edit Distance

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.

You have the following 3 operations permitted on a word:

  • Insert a character
  • Delete a character
  • Replace a character
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Example 1:

    Input: word1 = "horse", word2 = "ros"
    Output: 3
    Explanation:
    horse -> rorse (replace 'h' with 'r')
    rorse -> rose (remove 'r')
    rose -> ros (remove 'e')
    Example 2:

    Input: word1 = "intention", word2 = "execution"
    Output: 5
    Explanation:
    intention -> inention (remove 't')
    inention -> enention (replace 'i' with 'e')
    enention -> exention (replace 'n' with 'x')
    exention -> exection (replace 'n' with 'c')
    exection -> execution (insert 'u')

To apply DP, we define the state dp[i][j] to be the minimum number of operations to convert word1[0..i) to word2[0..j).

For the base case, that is, to convert a string to an empty string, the mininum number of operations (deletions) is just the length of the string. So we have dp[i][0] = i and dp[0][j] = j.

For the general case to convert word1[0..i) to word2[0..j), we break this problem down into sub-problems. Suppose we have already known how to convert word1[0..i - 1) to word2[0..j - 1) (dp[i - 1][j - 1]), if word1[i - 1] == word2[j - 1], then no more operation is needed and dp[i][j] = dp[i - 1][j - 1].

If word1[i - 1] != word2[j - 1], we need to consider three cases.

Replace word1[i - 1] by word2[j - 1] (dp[i][j] = dp[i - 1][j - 1] + 1);

  • If word1[0..i - 1) = word2[0..j) then delete word1[i - 1] (dp[i][j] = dp[i - 1][j] + 1);
  • If word1[0..i) + word2[j - 1] = word2[0..j) then insert word2[j - 1] to word1[0..i) (dp[i][j] = dp[i][j - 1] + 1).
  • So when word1[i - 1] != word2[j - 1], dp[i][j] will just be the minimum of the above three cases.

如果最后两个字符(i,j)相等,最后两个字符就不要配对,所以等于minDistance(s1[0..i-1],s2[0…j-1]);

如果最后两个字符不相等: 说明要编辑,具体可以分为三种情况:

  • 如果 s1[i-1]和s2[j]可以配对,那我就删除s1[i]即可(删除);
  • 如果 s1[i]和s2[j-1]可以配对,那我就在s1的后面加上s2[j]即可(插入);
  • 如果 s1[i-1]和s2[j-1]可以配对,那我就把s1[i]修改成s2[j]即可;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 = 1; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 1; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; 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 - 1], min(dp[i][j - 1], dp[i - 1][j])) + 1;
}
}
}
return dp[m][n];
}
};

Note that each time when we update dp[i][j], we only need dp[i - 1][j - 1], dp[i][j - 1] and dp[i - 1][j]. We may optimize the space of the code to use only two vectors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<int> pre(n + 1, 0), cur(n + 1, 0);
for (int j = 1; j <= n; j++) {
pre[j] = j;
}
for (int i = 1; i <= m; i++) {
cur[0] = i;
for (int j = 1; j <= n; j++) {
if (word1[i - 1] == word2[j - 1]) {
cur[j] = pre[j - 1];
} else {
cur[j] = min(pre[j - 1], min(cur[j - 1], pre[j])) + 1;
}
}
fill(pre.begin(), pre.end(), 0);
swap(pre, cur);
}
return pre[n];
}
};

Or even just one vector.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size(), pre;
vector<int> cur(n + 1, 0);
for (int j = 1; j <= n; j++) {
cur[j] = j;
}
for (int i = 1; i <= m; i++) {
pre = cur[0];
cur[0] = i;
for (int j = 1; j <= n; j++) {
int temp = cur[j];
if (word1[i - 1] == word2[j - 1]) {
cur[j] = pre;
} else {
cur[j] = min(pre, min(cur[j - 1], cur[j])) + 1;
}
pre = temp;
}
}
return cur[n];
}
};
Donate? comment?