这是LeetCode的72题,好久没有做动态规划了,所以碰到这道题,第一反应完全没有想到动态规划,所以记录下来,以提示自己,同时也分享给大家,我写的不好,也可以参照官方题解
原题
72. 编辑距离
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 1:
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:
输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
解题思路
dp数组解释
题目就说了,这个一道动态规划问题,所以直接先上dp数组,我取名称:records,定义和特点如下
- records[i][j]:将word1前i个字符 和 word2 前j个字符编辑成相等,需要多少步
- records[i][j]中i每增加一1,就相当于word1的字符的下标右移动一位,这个是不需要步骤的,也就是解题的关键
递推公式
record[i][j]:数值的来源可以有3个
1. 在record[i][j-1]基础上 :直接插入一个字符,步骤需要+1
2. 从record[i-1][j-1]中来 : 这个要分2中情况,由于i增加了,所以word1[i] == word2[j],那么不增加任何步骤,还等于record[i-1][j-1],否则需要替换字符,步骤+1
3. 从record[i-1][j]中来 :这个i增加了1,所以需要删除新增加的字符,才能和原来相等,所以步骤+1
初始化数据
这里有2个特殊情况,可以提前初始化好
- records[0][j] :当空字符串word1变成word2需要的步骤,自然,word2有多少个字符,就需要多少步骤(全部是插入)
- records[i][0] :将word1变成空字符的需要的步骤,同上,全部是删除的步骤,长度和i相关
根据上面,大家可以手动的填一下dp数组,效果如下(网上找的图片,红框不用管):
代码
class Solution {
/*records[i][j]:将word1前i个字符 和 word2 前j个字符都相等,需要多少步
特点:records[i][j]中i每增加一1,相当于records[i-1][j]的基础上自动增加了一个word1的字符
record[i][j]:的来可以有3个方向
1. 从record[i][j-1]中直接插入一个字符,步骤需要+1
2. 从record[i-1][j-1]:这个要分2中情况,由于i增加了,所以word1[i] == word2[j],那么不增加任何步骤,还等于record[i-1][j-1],否则需要替换字符,步骤+1
3. 从record[i-1][j]中来:这个i增加了1,所以需要删除新增加的字符
预备工作:
要先初始化:
1.当空字符,变成word2需要的步骤,自然,word2有多少个字符,就需要多少步骤(全部是插入)
2. 将word1变成空字符的需要的步骤,同上,全部是删除的步骤
*/
public int minDistance(String word1, String word2) {
int m = word1.length() + 1;
int n = word2.length() + 1;
int[][] records = new int[m][n];
//records[i][j] 的值可以有下面3种情况转换而来
for(int i = 0; i < m;i++){
records[i][0] = i;
}
for(int j = 0;j < n;j++){
records[0][j] = j;
}
int min = 0;
for(int i = 1;i < m;i++){
for(int j = 1;j < n;j++){
if(word1.charAt(i-1) == word2.charAt(j-1)){
records[i][j] = records[i-1][j-1];
} else {
min = Math.min(records[i][j-1],records[i-1][j-1]);
records[i][j] = Math.min(min,records[i-1][j]) + 1;
}
}
}
return records[m-1][n-1];
}
}