给定两个单词 word1
和 word2
,返回使得 word1
和 word2
相同所需的最小步数。
每步 可以删除任意一个字符串中的一个字符。
示例 1:
输入: word1 = "sea", word2 = "eat" 输出: 2 解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"
示例 2:
输入:word1 = "leetcode", word2 = "etco" 输出:4
提示:
1 <= word1.length, word2.length <= 500
word1
和 word2
只包含小写英文字母dp[i][j]表示以下标i结尾的word1字符串和以下标j结尾的word2字符串,删除至相同所需的最小步骤。
如果word1[i]==word2[j],无需进行删除操作,那么dp[i][j] == dp[i-1][j-1];
如果word1[i] !=word2[j],那么dp[i][j]可以由三个方向推导出来:
1、删除word1[i],删除word2[j],两个步骤,即dp[i][j]=dp[i-1][j-1]+2;
2、删除word1[i],word2[j]继续匹配,一个步骤,即dp[i][j]=dp[i-1][j]+1;
3、删除word2[j],word1[i]继续匹配,一个步骤,即dp[i][j]=dp[i][j-1]+1;
所以dp[i][j]=max(dp[i-1][j-1]+2,dp[i-1][j]+1,dp[i][j-1]+1);
由递推公式可知,dp需要初始化第一行和第一列。
for(int j = 0; j < word2.length(); j++){
if(word1.charAt(0) == word2.charAt(j)){//如果相等,那么word1[0]和以下标j结尾的word2字符串相同所需的操作步骤为j,即删掉除word2[j]之前的所有字符。
dp[0][j] = j;
}else{//如果不相等,当j == 0 的时候,需要删除word1[0]和word2[0],2个步骤
//当j!=0时,在之前步骤的基础上,删除word2[j],加一个步骤。
if(j > 0) dp[0][j] = dp[0][j-1] + 1;
else dp[0][j] = 2;
}
}
for(int i = 0; i < word1.length(); i++){//第一列同理
if(word1.charAt(i) == word2.charAt(0)){
dp[i][0] = i;
}else{
if(i > 0) dp[i][0] = dp[i-1][0] + 1;
else dp[i][0] = 2;
}
}
word1和word2的哪个先遍历都无所谓,只要都是从前往后遍历。
代码如下:
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length()][word2.length()];
for(int j = 0; j < word2.length(); j++){
if(word1.charAt(0) == word2.charAt(j)){//如果相等,那么word1[0]和以下标j结尾的word2字符串相同所需的操作步骤为j,即删掉除word2[j]之前的所有字符。
dp[0][j] = j;
}else{//如果不相等,当j == 0 的时候,需要删除word1[0]和word2[0],2个步骤
//当j!=0时,在之前步骤的基础上,删除word2[j],加一个步骤。
if(j > 0) dp[0][j] = dp[0][j-1] + 1;
else dp[0][j] = 2;
}
}
for(int i = 0; i < word1.length(); i++){//第一列同理
if(word1.charAt(i) == word2.charAt(0)){
dp[i][0] = i;
}else{
if(i > 0) dp[i][0] = dp[i-1][0] + 1;
else dp[i][0] = 2;
}
}
for(int i = 1; i < word1.length(); i++) {
for(int j = 1; j < word2.length(); j++) {
if(word1.charAt(i) == word2.charAt(j)){//相等时由左上方推出来
dp[i][j] = dp[i-1][j-1];
}else{//不相等时由左方、上方、左上方推出来
dp[i][j] = Math.min(dp[i-1][j-1] + 2,Math.min(dp[i-1][j] + 1,dp[i][j-1] + 1));
}
}
}
return dp[word1.length()-1][word2.length()-1];
}
}
给你两个单词 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')
提示:
0 <= word1.length, word2.length <= 500
word1
和 word2
由小写英文字母组成dp[i][j]表示以下标i结尾的字符串word1转换成以下标j结束的字符串word2所需的最少操作步骤。
当word1[i]==word2[j]时,无需任何操作,即dp[i][j]=dp[i-1][j-1];
当word1[i]!=word2[j]时,可以有三种操作:
1、替换word1[i]元素,使之与word2[j]相等,即dp[i][j]=dp[i-1][j-1]+1;
2、删除word1[i]元素,即dp[i][j]=dp[i-1][j] + 1;
3、在word1[i]元素之后插入一个元素,使该元素与word2[j]相等,那么即dp[i][j]=dp[i][j-1]+1;
根据递推公式初始化dp数组的第一行和第一列。
boolean flag = false;
for(int j = 0; j < word2.length(); j++) {
if(word1.charAt(0) == word2.charAt(j)){//如果相等,那么word1[0]转化成以j结尾的word2字符串所需操作数为j,即添加j个数,注意j是从0开始的。
dp[0][j] = j;
flag = true;
}
else{//如果不相等,当word2[j]之前有出现过word1[0]时,只需操作j步,即在word1[0]添加j个数
//当word2[j]之前没有出现果word1[0]时,需要操作j+1步,即将word1[0]转化成word1[0],再添加j个数
if(flag) dp[0][j] = j;
else dp[0][j] = j + 1;
}
}
flag = false;
for(int i = 0; i < word1.length(); i++) {//初始化第一列同理
if(word1.charAt(i) == word2.charAt(0)){
dp[i][0] = i;
flag = true;
}
else{
if(flag) dp[i][0] = i;
else dp[i][0] = i + 1;
}
}
word1和word2哪个先遍历没关系,但都需从前往后遍历。
代码如下:
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()][word2.length()];
boolean flag = false;
for(int j = 0; j < word2.length(); j++) {
if(word1.charAt(0) == word2.charAt(j)){//如果相等,那么word1[0]转化成以j结尾的word2字符串所需操作数为j,即添加j个数,注意j是从0开始的。
dp[0][j] = j;
flag = true;
}
else{//如果不相等,当word2[j]之前有出现过word1[0]时,只需操作j步,即在word1[0]添加j个数
//当word2[j]之前没有出现果word1[0]时,需要操作j+1步,即将word1[0]转化成word1[0],再添加j个数
if(flag) dp[0][j] = j;
else dp[0][j] = j + 1;
}
}
flag = false;
for(int i = 0; i < word1.length(); i++) {//初始化第一列同理
if(word1.charAt(i) == word2.charAt(0)){
dp[i][0] = i;
flag = true;
}
else{
if(flag) dp[i][0] = i;
else dp[i][0] = i + 1;
}
}
for(int i = 1; i < word1.length(); i++) {
for(int j = 1; j < word2.length(); j++) {
if(word1.charAt(i) == word2.charAt(j)) {//如果相等,无需操作
dp[i][j] = dp[i-1][j-1];
}else{//如果不相等,再三个操作当中取步骤最少的操作数。
dp[i][j] = Math.min(dp[i-1][j-1] + 1, Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1));
}
}
}
// for(int i = 0; i < word1.length(); i++) {
// for(int j = 0; j < word2.length(); j++) {
// System.out.print(dp[i][j] + " ");
// }
// System.out.println();
// }
return dp[word1.length()-1][word2.length()-1];
}
}
这两道题比较类似,只要会其中一道题,两外一个也很容易想出来。