题目:
这算是动态规划我弄得十分透彻的一题了。
首先,我们回顾一下做动态规划题目的几个要点。
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;
}