给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。
数据范围:
,
要求:空间复杂度
,时间复杂度
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
// write code here
int l1=str1.length() ,l2=str2.length();
int[][] dp=new int[l1+1][l2+1];
for(int i=0;i<=l1;i++){
// 假设将str1编辑为str2,纵向为dc,横向为ic,对角为rc
for(int j=0;j<=l2;j++){
if(i==0){
dp[i][j]=ic*j;
}else if(j==0){
dp[i][j]=dc*i;
}else{
if(str1.charAt(i-1)==str2.charAt(j-1)){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=Math.min(Math.min(dp[i-1][j]+dc ,dp[i][j-1]+ic) ,dp[i-1][j-1]+rc);
}
}
}
}
return dp[l1][l2];
} public int minEditCost(String str1, String str2, int ic, int dc, int rc) {
int m = str1.length();
int n = str2.length();
// dp[i][j] 表示的意思就是将 str1 的前 i 哥字符转为 str2 的前 j 个字符需要的代价
int[][] dp = new int[m + 1][n + 1];
// 初始化第一行和第一列
for (int i = 1; i <= m; i++) {
dp[i][0] = i * dc; // 将 str1 的前 i 个字符删除,转为空字符串
}
for (int j = 1; j <= n; j++) {
dp[0][j] = j * ic; // 将空字符串转为 str2 的前 j 个字符,需要 j 次插入操作
}
// 动态规划计算最小编辑代价
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
int insert = dp[i][j - 1] + ic;
int delete = dp[i - 1][j] + dc;
int replace = dp[i - 1][j - 1] + rc;
dp[i][j] = Math.min(insert, Math.min(delete, replace));
}
}
}
return dp[m][n];
} public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
// write code here
int n1 = str1.length();
int n2 = str2.length();
int[][] dp = new int[n1 + 1][n2 + 1];
for (int i = 1; i <= n1; i++) dp[i][0] = dp[i - 1][0] + dc;
for (int i = 1; i <= n2; i++) dp[0][i] = dp[0][i - 1] + ic;
for (int i = 1; i <= n1; i++) {
for (int j = 1; j <= n2; 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 - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
dp[i][j] = Math.min(dp[i-1][j-1] + rc,Math.min(dp[i-1][j]+dc,dp[i][j-1]+ic));
}
}
}
return dp[n1][n2];
} public int minEditCost(String word1, String word2, int ic, int dc, int rc) {
// 输出将str1编辑成str2的最小代价
int n1 = word1.length();
int n2 = word2.length();
int[][] dp = new int[n1 + 1][n2 + 1];
// 第一行:是 word1 为空,变成 word2 最少步数,就是插入操作
for (int j = 1; j <= n2; j++) {
dp[0][j] = dp[0][j - 1] + ic;
}
// 第一列:是 word2 为空,需要的最少步数,就是删除操作
for (int i = 1; i <= n1; i++) {
dp[i][0] = dp[i - 1][0] + dc;
}
for (int i = 1; i <= n1; i++) {
for (int j = 1; j <= n2; j++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
// dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
dp[i][j] = Math.min(dp[i][j - 1] + ic, dp[i - 1][j] + dc);
int tmp = Math.min(dp[i - 1][j - 1] + rc, dp[i - 1][j - 1] + ic + dc);
dp[i][j] = Math.min(dp[i][j], tmp);
/* dp[i][j] = Math.min(Math.min(dp[i][j - 1] + ic, dp[i - 1][j] + dc),
Math.min(dp[i - 1][j - 1] + rc, dp[i - 1][j - 1] + ic + dc));*/
}
}
}
return dp[n1][n2];
} import java.util.*;
public class Solution {
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
if(str1==null || str2==null) return 0;
int m = str1.length(), n = str2.length();
int[][] dp = new int[m+1][n+1];
for(int i=0; i<=m; i++) dp[i][0] = i*dc;
for(int i=0; i<=n; i++) dp[0][i] = i*ic;
for(int i=1; i<=m; i++){
for(int j=1; j<=n; j++){
if(str1.charAt(i-1)==str2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}else{
int a = dp[i][j-1] + ic;
int b = dp[i-1][j] + dc;
int c = dp[i-1][j-1] + rc;
dp[i][j] = Math.min(a, Math.min(b, c));
}
}
}
return dp[m][n];
}
} dp[i][j]表示 str1[0: i] 变为 str2[0: j] 所需要的最少编辑次数
考虑下面几种情况:
dp[i - 1][j] ,只需减掉 str1[i] dp[i][j - 1] ,只需加上 str2[j] dp[i - 1][j - 1]str1[i] == str2[j] ,无需操作 str1[i] != str2[j] ,修改 str1[i] import java.util.*;
public class Solution {
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
int[][] dp = new int[str1.length() + 1][str2.length() + 1];
dp[0][0] = 0;
for (int i = 1; i <= str1.length(); i++) {
dp[i][0] = i * dc;
}
for (int i = 1; i <= str2.length(); i++) {
dp[0][i] = i * ic;
}
for (int i = 1; i <= str1.length(); i++) {
for (int j = 1; j <= str2.length(); j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
int ins = dp[i][j - 1] + ic; // 添加
int del = dp[i - 1][j] + dc; // 删除
int rep = dp[i - 1][j - 1] + rc; // 替换
dp[i][j] = Math.min(ins, Math.min(del, rep));
}
}
}
return dp[str1.length()][str2.length()];
}
}
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) {
int m=str1.length();
int n=str2.length();
char[]cs1=str1.toCharArray();
char[]cs2=str2.toCharArray();
//
int[][]dp=new int[m+1][n+1];
for(int i=0;i<=m;i++){
dp[i][0]=i*dc;
}
for(int i=0;i<=n;i++){
dp[0][i]=i*ic;
}
//初始化
//下面是递归
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(cs1[i-1]==cs2[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][j-1]+ic,dp[i-1][j-1]+rc));
}
}
}
return dp[m][n];
}
}
import java.util.*;
public class Solution {
public int min(int a,int b){
return a<b ? a:b;
}
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
// write code here
int[][] dp = new int[str1.length()+1][str2.length()+1];
//str1为空 ,变成str2 是插入操作
for(int i=0;i<dp[0].length;i++){
dp[0][i]=i*ic;
}
//str1非空 str2为空 是删除操作
for(int j=0;j<dp.length;j++){
dp[j][0]=j*dc;
}
for(int i=1;i<dp.length;i++){
for(int j=1;j<dp[0].length;j++){
if(str1.charAt(i-1)==str2.charAt(j-1)){//当前元素匹配
dp[i][j]=dp[i-1][j-1];
}else{//当前元素不匹配
//dp[i-1][j-1]+rc 在str1[0,i-1] 与str2[0,j-1]匹配的情况下需要替换,说明str1[i]需要
//dp[i-1][j]+dc str1[0,i-1] 与str2[0,j]匹配的情况下需要删除,说明str1[i]多余了
//dp[i][j-1]+ic str1[0,i] 与str2[0,j-1]匹配的情况下需要增加,说明str[i]之后还得补一个元素。
dp[i][j]=min(dp[i-1][j-1]+rc,min(dp[i-1][j]+dc,dp[i][j-1]+ic ));
}
}
}
return dp[str1.length()][str2.length()];
}
} /*
在我看来,此题找状态转移方程是较麻烦的部分,
因此将我理解的三种情况的具体含义记录下来,供网友们参考。
1. dp[i][j-1]+ic: 当str1[i]已经和str2[j-1]匹配时,
为使str1[i]和str2[j]匹配,应在str1中插入str2的第j个元素。
2. dp[i-1][j]+dc: 当str1[i-1]已经和str2[j]匹配时,
为使str1[i]和str2[j]匹配,应删除str1中的第i个元素。
3. dp[i-1][j-1]+rc:当str1[i-1]已经和str2[j-1]匹配时,
由于str1[i]!=str2[j],为使str1[i]和str2[j]匹配,应将str1的
第i个元素替换成str2的第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 n1= str1.length();
int n2= str2.length();
if(n1==0) return n2*ic;
if(n2==0) return n1*dc;
int[][] dp=new int[n1+1][n2+1];
for (int i=0;i<n1;i++){
dp[i][0]=i*dc;
}
for (int i=0;i<n2;i++){
dp[0][i]=i*ic;
}
for (int i=1;i<=n1;i++){
for (int j=1;j<=n2;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][j-1]+ic, dp[i-1][j-1]+rc));
}
}
}
return dp[n1][n2];
}
}
import java.util.*;
public class Solution{
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
if(str1.length()==0)return str2.length()*ic;
if(str2.length()==0)return str1.length()*dc;
int [][]dp=new int[str1.length()+1][str2.length()+1];
int l1=str1.length();
int l2=str2.length();
dp[0][0]=0;
for(int i=1;i<=l1;i++)dp[i][0]=i*dc;
for(int j=1;j<=l2;j++)dp[0][j]=j*ic;
for(int i=1;i<=l1;i++)
{
for(int j=1;j<=l2;j++)
{
if(str1.charAt(i-1)==str2.charAt(j-1))dp[i][j]=dp[i-1][j-1];
else
{
//替换
int choice1=dp[i-1][j-1]+rc;
//删除
int choice2=dp[i-1][j]+dc;
//插入
int choice3=dp[i][j-1]+ic;
dp[i][j]=Math.min(Math.min(choice1,choice2),choice3);
}
}
}
return dp[l1][l2];
}
}
f(x,y):str1 0到x位置字符串str1[0..x] 与 str2中0到y位置字符串str2[0,y] 转换最低代价
如果str1[x] = str2[y] 那么 f(x,y) = f(x-1, y-1)
否则 f(x, y)就等于从
- str1[0...x-1]到str2[0...y-1]转换最低代价 + 一步替换操作代价值,
- str1[0...x-1]到str2[0...y]转换最低代价 + 一步删除操作代价值,
- str1[0...x]到str2[0...y-1]转换最低代价 + 一步插入操作代价值
三种选择中取值最小的情况,即,min( f(x-1, y-1) + a f(x, y-1) + b f(x-1, y) + c )
/**
* 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 l1 = str1.length();
int l2 = str2.length();
int[][] dp = new int[l1 + 1][l2 + 1];
for(int i=0; i< l1; ++i){
dp[i][0] = i * dc;
}
for(int i=0; i< l2; ++i){
dp[0][i] = i * ic;
}
for (int i = 1; i <= l1; ++i) {
for (int j = 1; j <= l2; ++j) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = getMin(
// 替换
dp[i - 1][j - 1] + rc,
// 插入
dp[i][j - 1] + ic,
// 删除
dp[i - 1][j] + dc
);
}
}
}
return dp[l1][l2];
}
public int getMin(int a, int b, int c) {
return a < b ?
a < c ? a : c
:
b < c ? b : c;
}
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
int n1=str1.length(),n2=str2.length();
int[][]dp=new int[n1+1][n2+1];//表明分别处理到str1和str2中i和j个元素的最小代价
for(int i=0;i<n1;i++) dp[i][0]=dc*i;
for(int i=0;i<n2;i++) dp[0][i]=ic*i;
for(int i=1;i<=n1;i++){
for(int j=1;j<=n2;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][j-1]+ic,dp[i-1][j-1]+rc));
}
}
return dp[n1][n2];
}
public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
//dp[i][j] 两个串的字符指针位于ij位置时的最小编辑距离 注意预留空的一行一列
int[][] dp = new int[str1.length()+1][str2.length()+1];
//初态:第一行第一列需要初始化
//dp[i][0] 表示 第一列 以及 str1串有字符i个 str2有0个 如何从Str1变到str2的状态? 删!
for (int i = 0; i <= str1.length(); i++) {
dp[i][0] = i*dc;
}
//dp[0][j] 表示 第一行 以及 str1串有字符0个 str2有j个 如何从Str1变到str2的状态? 增!
for (int j = 0; j <=str2.length(); j++) {
dp[0][j] = j*ic;
}
//转移方程: 记住所有的dp操作以操作str1为基准
for (int i = 1; i <= str1.length(); i++) {
for (int j = 1; j <= str2.length(); j++) {
if (str1.charAt(i-1)==str2.charAt(j-1)) dp[i][j] = dp[i-1][j-1];
else {
//三种情况:替换dp[i-1][j-1]+rc,增加dp[i][j-1]+ic,减少dp[i-1][j]+dc
dp[i][j]=Math.min(dp[i-1][j-1]+rc,Math.min(dp[i-1][j]+dc,dp[i][j-1]+ic));
}
}
}
return dp[str1.length()][str2.length()];
} 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) {
int n = str1.length(), m = str2.length();
int[][] dp = new int[n + 1][m + 1];
for (int i = 0; i <= m; i++) dp[0][i] = i * ic;
for (int i = 0; i <= n; i++) dp[i][0] = i * dc;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int insert = dp[i][j - 1] + ic;
int delete = dp[i - 1][j] + dc;
int update = dp[i - 1][j - 1];
if (str1.charAt(i - 1) != str2.charAt(j - 1)) update += rc;
dp[i][j] = Math.min(insert, Math.min(delete, update));
}
}
return dp[n][m];
}
} for (int i = 1; i <= ch1.length; i++) {
for (int j = 1; j <= ch2.length; j++) {
int flag = rc;
if (ch1[i - 1] == ch2[j - 1]) {
flag = 0;
}
dp[i][j] = Math.min(dp[i - 1][j - 1] + flag, Math.min(dp[i - 1][j] + dc, dp[i][j - 1] + ic));
}
} 但是如果换成i 在内测就会超时,不知道为什么。还有,是最近又加了test case了吗,为什么我的跑出来都1600ms+for (int j = 1; j <= ch2.length; j++) {
for (int i = 1; i <= ch1.length; i++) {
int flag = rc;
if (ch1[i - 1] == ch2[j - 1]) {
flag = 0;
}
dp[i][j] = Math.min(dp[i - 1][j - 1] + flag, Math.min(dp[i - 1][j] + dc, dp[i][j - 1] + ic));
}
}