给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。
数据范围:
,
要求:空间复杂度
,时间复杂度
class Solution {
public:
/**
* 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整型
*/
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[N][M];
dp[0][0] = str1[0] == str2[0] ? 0 : rc;
for(int i = 1; i < N; i++){
if(str1[i] == str2[0]){
dp[i][0] = i * dc;
}
else{
dp[i][0] = min(dp[i-1][0] + dc, rc + i*dc);
}
}
for(int j = 1; j < M; j++){
if(str1[0] == str2[j]){
dp[0][j] = j * ic;
}
else{
dp[0][j] = min(dp[0][j-1] + ic, rc + j*ic);
}
}
for(int i = 1; i < N; i++){
for(int j = 1; j < M; j++){
dp[i][j] = min(dp[i-1][j] + dc, dp[i][j-1] + ic);
if(str1[i] == str2[j]){
dp[i][j] = min(dp[i][j], dp[i-1][j-1]);
}
else{
dp[i][j] = min(dp[i][j], dp[i-1][j-1] + rc);
}
}
}
return dp[N-1][M-1];
}
}; 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();
int[][] dp = new int[m + 1][n + 1]; // 行是str1,列是str2,题目要求把str1编辑成str2
for (int i = 1; i <= m; i++) dp[i][0] = dp[i - 1][0] + dc; // str1 位置 i 字符 变成 str2 空字符 —— 需要delete
for (int j = 1; j <= n; j++) dp[0][j] = dp[0][j - 1] + ic; // str1 空字符 变成 str2 位置 i 字符 —— 需要insert
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
// 字符相同,无需花费cost
dp[i][j] = dp[i - 1][j - 1];
} else {
// 在insert,delete 和 replace中找到 cost 最小的一个
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[m][n];
}
} 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];
}
} class Solution {
public:
/**
* 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整型
*/
int minEditCost(string str1, string str2, int ic, int dc, int rc) {
int len1=str1.size(),len2=str2.size();
vector<vector<int>> dp(len1+1,vector<int>(len2+1,0));
for(int i=1;i<=len2;i++) {
dp[0][i]=ic*i; //只能增加
}
for(int i=1;i<=len1;i++) {
dp[i][0]=dc*i; //只能删除
}
for(int i=1;i<=len1;i++) {
for(int j=1;j<=len2;j++) {
dp[i][j]=min(dp[i-1][j]+dc,dp[i][j-1]+ic);
int t=dp[i-1][j-1]+((str1[i-1]==str2[j-1])?0:rc);
dp[i][j]=min(t,dp[i][j]);
// cout<<"("<<i<<","<<j<<"):"<<dp[i][j]<<endl;
}
}
return dp[len1][len2];
}
}; 以 word1 为 "horse",word2 为 "ros",且 dp[5][3] 为例,即要将 word1的前 5 个字符转换为 word2的前 3 个字符,也就是将 horse 转换为 ros,因此有:
(1) dp[i-1][j-1],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 2 个字符 ro,然后将第五个字符 word1[4](因为下标基数以 0 开始) 由 e 替换为 s(即替换为 word2 的第三个字符,word2[2])
(2) dp[i][j-1],即先将 word1 的前 5 个字符 horse 转换为 word2 的前 2 个字符 ro,然后在末尾补充一个 s,即插入操作
(3) dp[i-1][j],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 3 个字符 ros,然后删除 word1 的第 5 个字符
class Solution {
public:
int minEditCost(string str1, string str2, int ic, int dc, int rc) {
if(str1==""&&str2=="") return 0;
int len1 = str1.size();
int len2 = str2.size();
//想清楚状态矩阵的定义,下标代表长度!!
int dp[len1+1][len2+1];
for(int i=0;i<=len1;i++){
dp[i][0] = i*dc;//str1所有字符全部删除变成str2
}
for(int j=0;j<=len2;j++){
dp[0][j] = j*ic;//空字符串str1全部插入变成str2
}
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(str1[i-1]==str2[j-1]) dp[i][j] = dp[i-1][j-1];
else{
//等价于str1的前i-1个字符和str2的前j-1个字符编辑距离的子问题。
//即对于str1的第i个字符'X',对于str2的第j个字符'W',我们在str1的末尾'X'替换为字符'W',
//那么dp[i][j]最小可以为dp[i-1][j-1]+rc;
int choice1 = dp[i-1][j-1] + rc;//替换
//等价于str1的前i个字符和str2的前j-1个字符编辑距离的子问题。
//即对于str2的第j个字符'X',我们在str1的末尾添加了一个相同的字符'X',
//那么dp[i][j]最小可以为dp[i][j-1]+ic;
int choice2 = dp[i][j-1]+ic;//插入
//等价于str1的前i-1个字符和str2的前j个字符编辑距离的子问题。
//即对于str1的第i个字符'X',我们在str2的末尾添加了一个相同的字符'X',等价于在str1的末尾删除了该字符'X',
//那么dp[i][j]最小可以为dp[i][j-1]+dc;
int choice3 = dp[i-1][j]+dc;//删除
dp[i][j] = min(choice1,min(choice2,choice3));
}
}
}
return dp[len1][len2];
}
}; /**
* 牛客网:https://www.nowcoder.com/practice/05fed41805ae4394ab6607d0d745c8e4?tpId=191&tags=&title=&diffculty=0&judgeStatus=0&rp=1
* 每次操作都有对应的 cost
* 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整型
*
* 解法参考 leetcode 72. 编辑距离
* 本题比leetcode原题中增加了每种操作的代价。
* 原题的每种操作代价都是1
* dp[i][j] 表示 word1[0~i] 变成 word2[0~j] 需要的操作次数.
* dp[i][j] = 1 + Math.min(dp[i-1][j], Math.min(dp[i][j-1], dp[i-1][j-1]));
* 其中:已知 dp[i-1][j] 则 dp[i][j] 删除一个元素变成 dp[i-1][j] ,由 dp[i][j-1] 插入一个字符,由 dp[i-1][j-1] 替换一个元素
*
*/
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 n1 = str1.length(), n2 = str2.length();
// dp[0][0] 表示空字符串变成空字符串的代价(0),可以简化操作
int[][] dp = new int[n1 + 1][n2 + 1];
// 初始化:
// 1、由 str1 变成空字符串的代价
for (int i = 0; i <= n1; i++) dp[i][0] = i * dc;
// 2、由空字符串变成 str2 的代价
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];
} class Solution {
public:
/**
* 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整型
*/
int minEditCost(string a, string b, int ic, int dc, int rc) {
int n = a.size(), m = b.size();
a = ' ' + a, b = ' ' + b;
// f[i][j] : 将a[1 - i]变成b[1 - j]的的所有按顺序操作方案的最小值
vector<vector<int>> f(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; ++i) f[i][0] = i * dc;
for (int i = 1; i <= m; ++i) f[0][i] = i * ic;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1];
else {
int t1 = f[i - 1][j] + dc;
int t2 = f[i][j - 1] + ic;
int t3 = f[i - 1][j - 1] + rc;
f[i][j] = min(t1, min(t2, t3));
}
}
}
return f[n][m];
}
}; [LeetCode72:](https://leetcode-cn.com/problems/edit-distance/)class Solution: def minEditCost(self , str1 , str2 , ic , dc , rc ): str1_length = len(str1) str2_length = len(str2) dp = [[0 for i in range(str2_length)] for j in range(str1_length)] # str1的前i个数转换为str2的前j个数的最小cost for j in range(str2_length): dp[0][j] = dp[0][j - 1] + ic for i in range(str1_length): dp[i][0] = dp[i - 1][0] + dc dp[0][0] = 0 if str1[0] == str2[0] else min(rc, dc + ic) # 如果第一个数相等,则是为0,反之,则是替换或删除+增加的最小值 for i in range(1, str1_length): for j in range(1, str2_length): cost = 0 if str1[i] == str2[j] else min(rc, dc + ic) dp[i][j] = min(dp[i-1][j-1] + cost, dp[i-1][j] + dc, dp[i][j-1] + ic) # 3种情况 return dp[str1_length-1][str2_length-1]
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 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整型
*/
int minEditCost(string str1, string str2, int ic, int dc, int rc) {
// write code here
int m = str1.size(), n = str2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
// 以i为基准操作变为str2,插入i用ic,删除i用dc,替换i用rc
for (int i = 0; i <= m; i++)
dp[i][0] = i * dc;
for (int j = 0; j <= n; j++)
dp[0][j] = j * ic;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (str1[i - 1] == str2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
// 以i为基准操作变为str2,插入i用ic,删除i用dc,替换i用rc
dp[i][j] = min({dp[i][j - 1] + ic, dp[i - 1][j] + dc, dp[i - 1][j - 1] + rc});
}
}
return dp[m][n];
}
}; class Solution {
public:
int minEditCost(string str1, string str2, int ic, int dc, int rc) {
int len1 = str1.length();
int len2 = str2.length();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
for (int i = 1; i <= len1; i++){
dp[i][0] = i * dc;
}
for (int j = 1; j <= len2; j++){
dp[0][j] = j * ic;
}
for (int i = 1; i <= len1; i++)
for (int j = 1; j <= len2; j++){
if (str1[i - 1] == str2[j - 1])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = min({dp[i][j - 1] + ic, dp[i - 1][j] + dc, dp[i -1][j - 1] + rc});
}
return dp[len1][len2];
}
}; 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];
} /**
* 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整型
*/
int minEditCost(char* s, char* t, int ic, int dc, int rc ) {
// write code here
int m = strlen(s);
int n = strlen(t);
// if (m >= n + 2)
// return false;
int** mined = (int**)malloc(sizeof(int*) * (m + 1));
for (int i = 0; i <= m; i++) {
mined[i] = (int*)calloc(n + 1, sizeof(int));
}
for (int ii = 1; ii <= m; ii++) {
mined[ii][0] = ii*dc;
}
for (int iii = 1; iii <= n; iii++) {
mined[0][iii] = iii*ic;
}
for (int j = 1; j <= m; j++) {
for (int k = 1; k <= n; k++) {
if (s[j - 1] == t[k - 1]) {
mined[j][k] = mined[j - 1][k - 1];
} else {
if ((mined[j - 1][k - 1] + rc) < (mined[j][k - 1] + ic)) {
if ((mined[j - 1][k - 1] + rc) < (mined[j - 1][k] + dc)) {
mined[j][k] = (mined[j - 1][k - 1] + rc);
} else {
mined[j][k] = (mined[j - 1][k] + dc);
}
} else {
if ((mined[j][k - 1] + ic) < (mined[j - 1][k] + dc)) {
mined[j][k] = (mined[j ][k - 1] + ic);
} else {
mined[j][k] = (mined[j - 1][k] + dc);
}
}
//mined[j][k]=((mined[j-1][k-1]+1)>(mined[j][k-1]+1):)
}
}
}
// if (mined[m][n] == 1)
// return true;
return mined[m][n];
} class Solution: def minEditCost(self , str1: str, str2: str, ic: int, dc: int, rc: int) -> int: # write code here m = len(str1) n = len(str2) dp = [[0 for j in range(n + 1)] for i in range(m + 1)] for i in range(1, m + 1): dp[i][0] = dp[i - 1][0] + dc for j in range(1, n + 1): dp[0][j] = dp[0][j - 1] + ic for i in range(1, m + 1): for j in range(1, n + 1): if str1[i - 1] == str2[j - 1]: dp[i][j] = dp[i - 1][j - 1] else: dp[i][j] = min(dp[i - 1][j] + dc, dp[i][j - 1] + ic, dp[i - 1][j - 1] + rc) return dp[-1][-1]二维动态规划