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
===========
毫无思路,学习code ganker
http://codeganker.blogspot.com/2014/04/edit-distance-leetcode.html#comment-form
以及Discuss https://leetcode.com/discuss/17997/my-accepted-java-solution
This is a very interesting question and I found a youtube video that helps a lot. Basically the idea is to build up the solution step by step and keep track of the previous optimal solution in a 2D array. In this 2D array dp, dp[i][j] means the operation needed to transform word1(0, i) to word2(0,j).
There can be three conditions:
1, word1[i] == word2[j] : then no operation needed. dp[i][j] == dp[i-1][j-1]
2, Do one operation on word1[i-1][j]. dp[i][j] = dp[i-1][j] + 1
3, Do one operation on word2[i][j-1]. dp[i][j] = dp[i][j-1] + 1
4, 补充一点 replace操作: dp[i][j] = dp[i - 1][j - 1] + 1
for 2 and 3, the reason it works is that we know the optimal ways to transfrom word1(0,i) to word2(0,j-1) and word1(0,i-1) to word(0,j) ( Delete ("abc" to "ab") or Insert ("ab" to "abc") ). Now all we need to one more operation.
===========
具体到代码实现又出现了新的问题:为什么二维数组 dp[i][j]的最左边一列和最上面一行要初始化成对应 i 和 j 的值呢?
比如 dp[i][0], 表示的意思是从word2长度为0时要变到位置i的word1, 则需要word1的当前长度步,也就是i的值。
时间复杂度双层循环 O(m * n)
public class Solution {
public int minDistance(String word1, String word2) {
if(word1.length() == 0){
return word2.length();
}
if(word2.length() == 0){
return word1.length();
}
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
for(int i = 0; i <= word1.length(); i++){
dp[i][0] = i;
}
for(int j = 0; j <= word2.length(); j++){
dp[0][j] = j;
}
for(int i = 1; i <= word1.length(); i++){
for(int j = 1; j <= word2.length(); j++){
if(word1.charAt(i - 1) == word2.charAt(j - 1)){
dp[i][j] = dp[i - 1][j - 1];
}else{
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i - 1][j - 1]), dp[i][j - 1]) + 1;
}
}
}
return dp[word1.length()][word2.length()];
}
}
接下来研究一下如何省空间,
dp[i][j]需要用到 i -1 和 j - 1的数据,所以只要维护前面一行的结果就ok了
每循环到新的一行, 初始化第一个元素, 即上面解法中设置第一列
public class Solution {
public int minDistance(String word1, String word2) {
if(word1.length() == 0){
return word2.length();
}
if(word2.length() == 0){
return word1.length();
}
int[] dp = new int[word2.length() + 1];
for(int i = 0; i <= word2.length(); i++){ // word2.length() is the column number
dp[i] = i; //initial the first row
}
for(int i = 1; i <= word1.length(); i++){ // word1.length() is the row number
int[] newDp = new int[word2.length() + 1];
newDp[0] = i; // initial the first column
for(int j = 1; j <= word2.length(); j++){
if(word1.charAt(i - 1) == word2.charAt(j - 1)){
newDp[j] = dp[j - 1];
}else{
newDp[j] = Math.min(Math.min(dp[j], dp[j - 1]), newDp[j - 1]) + 1;
}
}
dp = newDp;
}
return dp[word2.length()];
}
}
这样空间复杂度是O(n), n为word2的长度。
甚至可以优化到O(min), min为word1和word2中较短的长度,
参见Code Ganker大神的解法