1. 原题链接
2. 编辑距离(一)题解
题目描述
方法模板
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str1 string字符串
* @param str2 string字符串
* @return int整型
*/
public int editDistance(String str1, String str2) {
// write code here
}
题目分析
- 首先分析题目,看描述,应该是得用动态规划
- 动态规划第一步,定义dp数值的含义:二位数组,标识将字符串a从i长度变成字符串b的j长度的最少操作数
- 动态规划第二步,定义公式
- 当a[i] == b[j] 的时候,dp[i][j] = dp[i-1][j-1]
- 当a[i] != b[j] 的时候,我们需要进行插入、删除、替换操作分别是:
-
- 插入:dp[i][j] = dp[i][j-1] + 1:
例如下面两个字符串,abc 变成 abcd,在abc 和 abc对齐的基础上,需要插入一个d
abc
abcd
-
- 替换:dp[i][j] = dp[i-1][j-1] + 1
例如下面两个字符串,abc 变成 abcd,在abc 和 abc对齐的基础上,需要把t替换成d
abct
abcd
-
- 删除:dp[i][j] = dp[i-1][j] + 1
例如下面两个字符串,abc 变成 abcd,在abc 和 abc对齐的基础上,需要把t删除
abct
abc
-
- 最后我们在什么三个操作里面选取一个最小值
- 动态规划第三步,确定递推公式
dp[i][j] = dp[i-1][j-1]; //a[i] == b[j]
dp[i][j] = min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1]) + 1; //a[i] != b[j]
- 动态规划第5步,确定边界条件
- 当字符串a的长度为0时,dp[0][j] = j;
- 当字符串b的长度为0时,dp[i][0] = i;
最终代码
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param str1 string字符串
* @param str2 string字符串
* @return int整型
*/
public int editDistance(String str1, String str2) {
// write code here
int n = str1.length();
int m = str2.length();
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
dp[i][0] = i;
}
for (int i = 1; i <= m; i++) {
dp[0][i] = i;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = Math.min(dp[i-1][j], Math.min(dp[i-1][j-1], dp[i][j -1])) + 1;
}
}
}
return dp[n][m];
}
}
3. 编辑距离(二)题解
题目描述
方法模板
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
// write code here
}
题目分析
相对于编辑距离(一),只是插入、替换、删除的操作的代价从都是1 变成了可定义,那么我们的分析如下:
- 首先分析题目,看描述,还是是得用动态规划
- 动态规划第一步,定义dp数值的含义:二位数组,标识将字符串a从i长度变成字符串b的j长度的最少操作代价
- 动态规划第二步,定义公式
- 当a[i] == b[j] 的时候,dp[i][j] = dp[i-1][j-1]
- 当a[i] != b[j] 的时候,我们需要进行插入、删除、替换操作分别是:
-
- 插入:dp[i][j] = dp[i][j-1] + ic:
例如下面两个字符串,abc 变成 abcd,在abc 和 abc对齐的基础上,需要插入一个d
abc
abcd
-
- 替换:dp[i][j] = dp[i-1][j-1] + rc
例如下面两个字符串,abc 变成 abcd,在abc 和 abc对齐的基础上,需要把t替换成d
abct
abcd
-
- 删除:dp[i][j] = dp[i-1][j] + dc
例如下面两个字符串,abc 变成 abcd,在abc 和 abc对齐的基础上,需要把t删除
abct
abc
-
- 最后我们在什么三个操作里面选取一个最小值
- 动态规划第三步,确定递推公式
dp[i][j] = dp[i-1][j-1]; //a[i] == b[j]
dp[i][j] = min(dp[i-1][j] + dc, dp[i-1][j-1] + rc, dp[i][j-1] + ic); //a[i] != b[j]
- 动态规划第5步,确定边界条件
- 当字符串a的长度为0时,dp[0][j] = j * ic;
- 当字符串b的长度为0时,dp[i][0] = i * dc;
主要变化的是递推公式a[i]!=b[j]时的取值和边界的取值
最终代码
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* min edit cost
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @param ic int整型 insert cost
* @param dc int整型 delete cost
* @param rc int整型 replace cost
* @return int整型
*/
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
// write code here
int n = str1.length();
int m = str2.length();
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
dp[i][0] = i * dc;
}
for (int i = 1; i <= m; i++) {
dp[0][i] = i * ic;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = Math.min(dp[i-1][j] + dc, Math.min(dp[i-1][j-1] + rc, dp[i][j -1] + ic));
}
}
}
return dp[n][m];
}
}