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
思路
STANFORD课件
https://web.stanford.edu/class/cs124/lec/med.pdf
Youtube视频
ttps://www.youtube.com/watch?v=Xxx0b7djCrs
复杂度
时间 O(NM) 空间 O(NM)
假设dp[i-1][j-1]表示一个长为i-1的字符串str1变为长为j-1的字符串str2的最短距离,如果我们此时想要把str1a这个字符串变成str2b这个字符串,我们有如下几种选择:
- 替换: 在str1变成str2的步骤后,我们将str1a中的a替换为b,就得到str2b (如果a和b相等,就不用操作)
- 增加: 在str1a变成str2的步骤后,我们再在末尾添加一个b,就得到str2b (str1a先根据已知距离变成str2,再加个b)
- 删除: 在str1变成str2b的步骤后,对于str1a,我们将末尾的a删去,就得到str2b (str1a将a删去得到str1,而str1到str2b的编辑距离已知)
根据这三种操作,我们可以得到递推式
- 若a和b相等:
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i][j])
- 若a和b不相等:
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i][j]+1)
初始化:
因为将一个非空字符串变成空字符串的最小操作数是字母个数(全删),反之亦然,所以:
dp[0][j]=j, dp[i][0]=i
最后我们只要返回dp[m][n]即可,其中m是word1的长度,n是word2的长度
public class Solution {
/*
* @param word1: A string
* @param word2: A string
* @return: The minimum number of steps.
*/
public int minDistance(String word1, String word2) {
// write your code here
//用DP,有三种情况
int len1 = word1.length();
int len2 = word2.length();
int[][] distance = new int[len1 + 1][len2 + 1];
//初始化,D[i][j]代表从word1的前i个字母 变形到 word2的前j个字母的距离
for (int i = 1; i <= len1; i++) {
distance[i][0] = i; //从word1的前i个字母 变形到word2的前0个字母 需要delete word1的前i个字母
}
for (int i = 1; i <= len2; i++) {
distance[0][i] = i;//从word1的前0个字母 变形到word2的前i个字母 需要insert word1的前i个字母
}
//计算D[LEN1][LEN2]
//必须从1开始,因为要计算D[i][j-1], D[i-1][j], D[i-1][j-1]
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
int insertDistance = distance[i][j - 1] + 1;
int deleteDistance = distance[i - 1][j] + 1;
int replaceDistance = distance[i - 1][j - 1] +
(word1.charAt(i - 1) == word2.charAt(j - 1) ? 0 : 1);
distance[i][j] = Math.min(insertDistance, Math.min(deleteDistance, replaceDistance));
}
}
return distance[len1][len2];
}
}