题目链接
leetcode在线oj题——编辑距离
题目描述
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
题目示例
输入:word1 = “horse”, word2 = “ros”
输出:3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
输入:word1 = “intention”, word2 = “execution”
输出:5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)
题目提示
- 0 <= word1.length, word2.length <= 500
- word1 和 word2 由小写英文字母组成
解题思路
我们创建一个二维数组arr,行数是第一个单词的长度加一,列数是第二个单词的长度加一,其中arr[0][0]代表空字符串
例如,word1 = “test”,word2 = “xiao”创建的数组长这样
数组中存放的数字是一个单词的部分片段到另一个单词的部分片段的编辑次数
例如arr[0][1]就是空字符串到“t”需要的编辑次数
arr[0][2]就是空字符串到“te”需要的编辑次数
arr[2][0]就是空字符串到“xi”需要的编辑次数
arr[3][2]就是“xia”到“te”需要的编辑次数
很显然,如果将空字符串变成“a”,需要一步添加操作,将空字符串变成“ab”,需要两步添加操作
因此,arr[i][0] = i,arr[0][i] = i
现在我们来研究arr[1][1]等于多少,也就是"x"变成“t”需要几步,分为下面三种情况:
- 情况一:先将x删除,再添加一个t
-情况二: 先加一个t,再将x删除 - 情况三:直接由x替换成t
先删除x相当于将x变成空字符串,也就是arr[1][0]
再添加一个t需要一步操作,因此第一种情况相当于arr[1][0] + 1 = 2
先添加t相当于将空字符串加一个“t”,也就是arr[0][1]
再删除一个x需要一步操作,因此第二种情况相当于arr[0][1] + 1 = 2
直接将x替换成t不需要对其他字符进行变更,因此相当于空字符串变成空字符串,然后再加上一个变更操作,因此第三种情况相当于arr[0][0] + 1 = 1
取这三种情况的最小值,因此arr[1][1] = 1
再研究一下arr[1][2]等于多少,也就是x变成te需要多少步
- 情况一: 先将x变成t,再添加e
- 情况二: 先添加t, 添加e,再删除x
- 情况三: 先添加t,再将x替换成e
先将x变成t对应arr[1][1],再添加一个e需要一步操作,因此第一种情况相当于arr[1][1] + 1 = 2
先添加t,添加e相当于将空字符串加“te”,也就是arr[0][2],再删除一个x需要一步操作,因此第二种情况相当于arr[0][2] + 1 = 3
先添加t相当于将空字符串加一个“t”,也就是arr[0][1]
再将x变成e需要一步操作,因此第二种情况相当于arr[0][1] + 1 = 2
我们可以找到规律:arr[i][j]的值是其左上角,上面,左面三个元素的较小者加1
arr[i][j] = Math.min(arr[i - 1][j], arr[i][j - 1], arr[i - 1][j - 1]) + 1;
但事实上,如果两个字符串的结尾字母是相同的,只需要将前几个字符变更就行了,例如"tea"和“cba”,我们并不需要替换最后一个字母
因此当最后一个字母相同时:
arr[i][j] = arr[i - 1][j - 1];
代码
class Solution {
public int minDistance(String word1, String word2) {
int row = word1.length();
int col = word2.length();
int[][] arr = new int[row + 1][col + 1];
for (int i = 0; i <= row; i++) {
arr[i][0] = i;
}
for (int i = 0; i <= col; i++) {
arr[0][i] = i;
}
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= col; j++) {
arr[i][j] = Math.min(arr[i - 1][j], arr[i][j - 1]) + 1;
if(word1.charAt(i - 1) == word2.charAt(j - 1)){
arr[i][j] = Math.min(arr[i][j] , arr[i - 1][j - 1]);
} else {
arr[i][j] = Math.min(arr[i][j] , arr[i - 1][j - 1] + 1);
}
}
}
return arr[row][col];
}
}