【动态规划】将str1变成str2的最小编辑代价

题目:
在这里插入图片描述
这算是动态规划我弄得十分透彻的一题了。

首先,我们回顾一下做动态规划题目的几个要点。

1.初始化条件,即动态矩阵的初始化

2.递推条件,即dp【i】【j】是怎么得来的

那么我们来分析一下这道题:

首先,动态规划处理字符串的时候,一般都会从空串起手,那么我们这题也从空串开始考虑。

计算上空串,并且将空串作为str1和str2的第一个字符。
那么dp【i】【j】就代表从str1【0…i】->(转变为)str2【0…j】需要的花费

这个花费来自于三个路径

第一个路径:由插入得到。str1【0…i】先编辑成str2【0…j-1】,再由str2【0…j-1】插入到str2【0…j】

dp【i】【j-1 】+ ic

第二个路径,由删除得到。str1【0…i】先编辑成str1【0…i-1】,再由str1【0…i-1】转变为str2【0…j】

即dp【i-1】【j】+dc

第三个路径,由替换得到。
而替换又分为两种情况:

第一种为当前字符串匹配的情况:那么就等于dp【i-1】【j-1】
第二种为当前字符串不匹配的情况:那么久等于dp【i-1】【j-1】+rc

那么,最后dp【i】【j】的值为这四种情况中的最小值。

那么初始化也就很简单了。

第一列为str1->删除变为空串的花费

第一行为str1->插入变为str2的花费

虽然有以上说明了,但是我还是举个例子来帮助大家理解吧。因为我自己看递推关系式的时候也没有很看懂。

比如
str1 = “ab12cd3”
str2 = “abcdf”
插入花费ic = 5
删除花费dc = 3
替换花费rc = 2

刚开始我们将空字符直接放在这两个字符串前面,作为str1【0】和str2【0】

那么第一列就为str1->空字符串的花费,为0 3 6 9 12 15 18 21;
第一行为空字符串->str2的花费 为0 5 10 15 25

那么,我们对于dp【1】【1】即str1 = ‘0a’ str2 = ‘0a’(0代表空字符串)
很容易得出dp【1】【1】为0,因为当前字符相等,属于第二种情况

问题的关键来了,对于dp【1】【2】 str1 = ‘0a’ str2='0ab’的情况呢?

第一个路径,插入操作,为0a->0ab 可以直接得出是0+5 = 5;
第二个路径,删除操作,为0a->0>0ab 从0->0ab是10,那么这里就会是13(因为删掉了a,然后从0->0ab
第三个路径为替换操作,由于当前字符不相等,属于第一种情况,那么就会等于dp【i-1】【j-1】+2 = 7;

那么这个位置的最小值就为5,即dp【i】【j】 = 5;

具体矩阵如下:
在这里插入图片描述
C++代码附带测试:

#include<iostream>
#include<cstring>
#include<Math.h>

using namespace std;


class Solution{
	public:
		int minEditCost(string str1, string str2, int ic, int dc, int rc) {
			//ic 插入一个字符 dc删除一个字符 rc替换一个字符 
        	int m = str1.length()+1;
        	int n = str2.length()+1;
        	
        	//需要留下空字符串的计算空间 
        	int dp[m][n] = {0};
        	
        	//初始化第一列,为str1的各个字符->空字符串的花费,全为删除 
			for(int i=0;i<m;i++){
				dp[i][0] = i*dc;
			} 
			
			//初始化第一行,为空字符串->str2的各个字符,全为插入操作
			for(int i=0;i<n;i++){
				dp[0][i] = i*ic;
			}
			
			//dp[i][j]表示字符串(包括空字符串,且空字符串记作第一个 0)str1[0..i]-st2[0..j]的最少花费 
			for(int i=1;i<m;i++){//遍历需要从1开始,因为空字符已经初始化过了 
				for(int j=1;j<n;j++){
					int dp1 = dp[i][j-1] + ic;//插入操作
					int dp2 = dp[i-1][j] + dc;//删除操作
					int dpx = min(dp1,dp2);
					
					//替换操作
					int dpy = 0;
					if(str1[i]==str2[j]){
						dpy = dp[i-1][j-1];//不需要任何操作 
					}else{
						dpy = dp[i-1][j-1]+rc;//需要一次替换
					}
					dp[i][j] = min(dpx,dpy);//为这四种路线中的最小值
					cout<<dp[i][j]<<" ";
				}
				cout<<endl;
			}
			return dp[m-1][n-1];
};
	private:
};


int main(){
	string str1 = "ab12cd3";
	string str2 = "abcdf";
	Solution solution;
	int cost = solution.minEditCost(str1,str2,5,3,2);
	cout<<endl;
	cout<<"str1->str2需要的最少花费为:"<<cost;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值