您的位置:首页 > 其它

leetcode 72. Edit Distance

2016-09-15 14:53 218 查看
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

例如:

word1:a

word2:ab

这样可以在word1后面增加一个字符b来使得word1变成word2。这时只需1步。

例如:

word1:mart

word2:karma

可以将word1的第一个字符‘m’换成‘k’,第4个字符’t’换成‘m’,最后增加一个字符’a’。这时只需3步。

例如:

word1:hehe123

word2:hehe

可以将word1后面的三个字符“123”全部删掉。这时只需3步。

递归代码(记忆化搜索优化)

public class Solution {
public static final int MAX_INT = 100000;
public static int[][] result;
public int search(int x, int y, String word1, String word2) {

if (x == 0 && y == 0) {
if (word1.charAt(x) == word2.charAt(y)) {
return 0;
} else {
return 1;
}
}

if (x < 0 && y >= 0) {
return y+1;  //增加
}
if (x >= 0 && y < 0) {
return x+1;  //删除
}

//记忆化搜索
if(result[x][y] >= 0) {
return result[x][y];
}

//这几个初始值,不要初始化为0,否则最终的结果是0
int a = MAX_INT, b = MAX_INT, c = MAX_INT, d = MAX_INT;
if (word1.charAt(x) == word2.charAt(y)) {
a = search(x-1, y-1, word1, word2);
}
b = search(x-1, y, word1, word2) + 1; //删除
c = search(x, y-1, word1, word2) + 1; //增加
d = search(x-1, y-1, word1, word2) + 1; //替换

result[x][y] = Math.min(Math.min(Math.min(a, b), c),d);

return result[x][y];
}

public int minDistance(String word1, String word2) {
if (word1.length() == 0 || word2.length() == 0) {
return Math.abs(word1.length() - word2.length());
}
result = new int[word1.length()][word2.length()];
for(int i = 0; i < word1.length(); i++) {
for(int j = 0; j < word2.length(); j++) {
result[i][j] = -1;
}
}
return search(word1.length()-1, word2.length()-1, word1, word2);
}
}


上面的代码是自己AC的,总感觉写的很戳,于是找了下网上的写法,发现差距不是一点半点。不能忘记历史,所以也粘贴过来了。

代码可以写的越来越好的。大牛也是这么练就的。

先上代码:

public int search(int x, int y, String word1, String word2) {
if ( x < 0) {
return y+1;
}
if (y < 0) {
return x+1;
}
if (result[x][y] >= 0) {
return result[x][y];
}
if (word1.charAt(x) == word2.charAt(y)) {
result[x][y] = search(x-1, y-1, word1, word2);
} else {
int a = 0, b = 0, c = 0;
//替换
a = search(x-1, y-1, word1, word2) + 1;
//增加
b = search(x, y-1, word1, word2) + 1;
//删除
c = search(x-1, y, word1, word2) + 1;
result[x][y] = Math.min(Math.min(a, b), c);
}
return result[x][y];
}

public int minDistance(String word1, String word2) {
result = new int[word1.length()][word2.length()];
for(int i = 0; i < word1.length(); i++) {
for(int j = 0; j < word2.length(); j++) {
result[i][j] = -1;
}
}
return search(word1.length()-1, word2.length()-1, word1, word2);
}


究其原因,还是没有理清问题,没有找准递推公式:



当word1的下标都小于0了,要变成word2,只要增加 字符就行了。

当word2的下标小于0了,word1要变成word2,只要删除 字符就行了。

递推代码

public int minDistance(String word1, String word2) {
if (word1.length() == 0 || word2.length() == 0) {
return Math.abs(word1.length() - word2.length());
}
result = new int[word1.length()+1][word2.length()+1];
for(int i = 0; i < word1.length()+1; i++) {
for(int j = 0; j < word2.length()+1; j++) {
result[i][j] = -1;
}
}

for (int j = 0; j < word2.length()+1; j++) {
result[0][j] = j;
}

int a = MAX_INT, b = MAX_INT, c = MAX_INT;
for (int i = 1; i < word1.length()+1; i++) {
result[i][0] = i;
for (int j = 1; j < word2.length()+1; j++) {
if (word1.charAt(i-1) == word2.charAt(j-1)) {
result[i][j] = result[i-1][j-1];
} else {
a = result[i-1][j] + 1; //删除
b = result[i][j-1] + 1; //增加
c = result[i-1][j-1] + 1; //替换
result[i][j] =  Math.min(Math.min(a, b), c);
}
}
}
return result[word1.length()][word2.length()];
}


递推代码也要表示出word1或者word2下标小于0的情况。但是数组的下标都是从0开始的,无法表示负数下标,因此可以用二维数组中,下标为0的表示单词没有字符了,也就是说,下标表示单词的字符个数。

这个问题详见这篇博文:

http://www.dreamxu.com/books/dsa/dp/edit-distance.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息