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
题目链接:https://leetcode.com/problems/edit-distance/
题目分析:经典动态规划问题,设dp[i][j]为第一个字符串到第i个位置,第二个字符串到第j个位置时所需的最小编辑距离,将word1编辑成word2,删除操作对应的转移方程为dp[i][j] = dp[i][j - 1] + 1,相当于不拿word1的第i个和word2的第j个比,直接将word2的第j个删除,增加操作对应的是dp[i][j] = dp[i - 1][j] + 1,相当于直接在i位置放j的最后一个字母,替换操作需要比较当前两个字符是否相同,转移时若末尾不同则dp[i][j]取三种操作的最小值,初始化dp[0][j] = j,dp[i][0] = i
4ms,时间击败94.32%
class Solution {
private int min3(int a, int b, int c) {
if (a <= b && a <= c) {
return a;
}
if (b <= a && b <= c) {
return b;
}
return c;
}
public int minDistance(String word1, String word2) {
int n = word1.length();
int m = word2.length();
int[][] dp = new int[n + 1][m + 1];
dp[0][0] = 0;
for (int i = 1; i <= n; i ++) {
dp[i][0] = i;
}
for (int j = 1; j <= m; j ++) {
dp[0][j] = j;
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = 1 + min3(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}
}
}
return dp[n][m];
}
}
空间优化成一维的做法
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = 1 + min3(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}
不难发现dp[i][j]的值只和其上方,左边以及左上的三个值有关,设dp[j]为当word1的前缀长分别为0到n时,其与word2到第j个字符的编辑距离,在每次对i进行循环时,需要更新dp[0]的值,其实是更新dp[i][0]的值,下面解释以下这行语句是如何等价到二维情况的
dp[j] = 1 + min3(dp[j], dp[j - 1], lu);
1. 左边的dp[j]自然就表示dp[i][j]
2. 右边的dp[j],因当前赋值号左边的dp[j]尚未被更新,故其值为i-1阶段算出的dp[j],即dp[i - 1][j]
3. 右边的dp[j - 1],这个很好理解,就是当前行的前一列的值,即dp[i][j - 1]
4. 右边的lu,lu指left up,首先是其初始值为i - 1,因为在边界上dp[i - 1][j - 1]就是dp[i - 1][0],值自然就是i - 1,之后每次更新时,需要先记录当前dp[j]的值,上面有解释,代表的其实是dp[i - 1][j],当j向后迭代到j+1时,当前的lu就是dp[i - 1][(j + 1) - 1]的值,也就是之前存的dp[i - 1][j],因此需要引入一个tmp变量进行滚动更新
综上可得
dp[j] = 1 + min3(dp[j], dp[j - 1], lu);
等价于
dp[i][j] = 1 + min3(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
5ms,时间击败77.2%(此题数据有增强过)
class Solution {
private int min3(int a, int b, int c) {
if (a <= b && a <= c) {
return a;
}
if (b <= a && b <= c) {
return b;
}
return c;
}
public int minDistance(String word1, String word2) {
int n = word1.length();
int m = word2.length();
int[] dp = new int[m + 1];
// init dp[0][0] ~ dp[0][m]
for (int j = 0; j <= m; j++) {
dp[j] = j;
}
for (int i = 1; i <= n; i++) {
dp[0] = i; // dp[i][0] => delete all word1[:i]
int lu = i - 1; // dp[i - 1][j - 1] (left, up)
for (int j = 1; j <= m; j++) {
int tmp = dp[j];
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[j] = lu;
} else {
dp[j] = 1 + min3(dp[j], dp[j - 1], lu);
}
lu = tmp;
}
}
return dp[m];
}
}