Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)
You have the following 3 operations permitted on a word:
a) Insert a character
b) Delete a character
c) Replace a character
给定一个源串和目标串,能够对源串进行如下操作:
1.在给定位置上插入一个字符
2.替换任意字符
3.删除任意字符
This is a classic problem of Dynamic Programming. We define the state dp[i][j]
to be the minimum number of operations to convert word1[0..i - 1]
to word2[0..j - 1]
. The state equations have two cases: the boundary case and the general case. Note that in the above notations, both i
and j
take values starting from 1
.
For the boundary case, that is, to convert a string to an empty string, it is easy to see that the mininum number of operations to convert word1[0..i - 1]
to ""
requires at least i
operations (deletions). In fact, the boundary case is simply:
dp[i][0] = i
;dp[0][j] = j
.Now let's move on to the general case, that is, convert a non-empty word1[0..i - 1]
to another non-empty word2[0..j - 1]
. Well, let's try to break this problem down into smaller problems (sub-problems). Suppose we have already known how to convert word1[0..i - 2]
to word2[0..j - 2]
, which is dp[i - 1][j - 1]
. Now let's consider word[i - 1]
and word2[j - 1]
. If they are euqal, then no more operation is needed and dp[i][j] = dp[i - 1][j - 1]
. Well, what if they are not equal?
If they are not equal, we need to consider three cases:
word1[i - 1]
by word2[j - 1]
(dp[i][j] = dp[i - 1][j - 1] + 1 (for replacement)
);word1[i - 1]
and word1[0..i - 2] = word2[0..j - 1]
(dp[i][j] = dp[i - 1][j] + 1 (for deletion)
);word2[j - 1]
to word1[0..i - 1]
and word1[0..i - 1] + word2[j - 1] = word2[0..j - 1]
(dp[i][j] = dp[i][j - 1] + 1 (for insertion)
).Make sure you understand the subtle differences between the equations for deletion and insertion. For deletion, we are actually converting word1[0..i - 2]
to word2[0..j - 1]
, which costs dp[i - 1][j]
, and then deleting the word1[i - 1]
, which costs 1
. The case is similar for insertion.
Putting these together, we now have:
dp[i][0] = i
;dp[0][j] = j
;dp[i][j] = dp[i - 1][j - 1]
, if word1[i - 1] = word2[j - 1]
;dp[i][j] = min(dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1, dp[i][j - 1] + 1)
, otherwise.The above state equations can be turned into the following code directly.
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
// 注意长度,字符有0长度
//dp[i][j] 代表最小操作数(步骤),从 word1[0..i-1]转化为 word2[0..j-1].
int[][] dp = new int[m + 1][n + 1];
// dp[i][0]=i表示,字符长度为i变为长度0,delete i个子符,需要i步
// dp[0][i]=i表示,字符长度为0变为长度i,insert i个子符,需要i步
for (int i = 0; i <= m; i++)
dp[i][0] = i;
for (int i = 0; i <= n; i++)
dp[0][i] = i;
//注意<=
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) {
//如果前i-1
if (word1.charAt(i - 1) == word2.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = 1 +
Math.min(dp[i - 1][j - 1],
Math.min(dp[i][j - 1], dp[i - 1][j]));
}
return dp[m][n];
}
从0开始
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] cost = new int[m + 1][n + 1];
for(int i = 0; i <= m; i++)
cost[i][0] = i;
for(int i = 1; i <= n; i++)
cost[0][i] = i;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(word1.charAt(i) == word2.charAt(j))
cost[i + 1][j + 1] = cost[i][j];
else {
int a = cost[i][j];
int b = cost[i][j + 1];
int c = cost[i + 1][j];
cost[i + 1][j + 1] = a < b ? (a < c ? a : c) : (b < c ? b : c);
cost[i + 1][j + 1]++;
}
}
}
return cost[m][n];
}
dfs+记忆搜索算法
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] cache = new int[m + 1][n + 1];
return minDistance(word1, 0, word2, 0, cache);
}
private int minDistance(String word1, int a, String word2, int b, int[][] cache) {
if (a == word1.length() && b == word2.length())
return 0;
if (a == word1.length())
return word2.length() - b;
if (b == word2.length())
return word1.length() - a;
if (cache[a][b] != 0)
return cache[a][b];
if (word1.charAt(a) == word2.charAt(b))
return cache[a][b] =
minDistance(word1, a + 1, word2, b + 1, cache);
else
return cache[a][b] =
Math.min(Math.min
(minDistance(word1, a + 1, word2, b + 1, cache),
minDistance(word1, a, word2, b + 1, cache)),
minDistance(word1, a + 1, word2, b, cache))
+ 1;
}
https://discuss.leetcode.com/topic/17639/20ms-detailed-explained-c-solutions-o-n-space