对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。
测试样例:
"abc",3,"adc",3,5,3,100
返回:8
对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。保证两串长度均小于等于300,且三种代价值均小于等于100。
"abc",3,"adc",3,5,3,100
返回:8
package alex.suda.dp;
import java.util.Scanner;
public class test4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
String A = scanner.next();
int m = scanner.nextInt();
String B = scanner.next();
int c0 = scanner.nextInt();
int c1 = scanner.nextInt();
int c2 = scanner.nextInt();
System.out.print(findMinCost(A, n, B, m, c0, c1, c2));
}
}
public static int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
// 设d[i][j]为将字符串A的1~i位和B的1~j位变为相同时的操作代价
// 注意题目是:A串变为B串 而不是将两个字符串变为相等
// d[i][j] = d[i-1][j-1], 如果A[i] = A[j]
// 否则可以: 1. A的末端插入B的最后一位
// 2.删除A的末端
// 3.修改A的末端为B的末端
int[][] d = new int[n + 1][m + 1];
// 初始化
for (int i = 0; i <= n; i++) {
d[i][0] = i * c1;
}
for (int j = 0; j <= m; j++) {
d[0][j] = j * c0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A.charAt(i - 1) == B.charAt(j - 1)) {
d[i][j] = d[i - 1][j - 1];
} else {
int cost1 = d[i][j - 1] + c0;// 插入时的代价
int cost2 = d[i - 1][j] + c1;// 删除的代价
int cost3 = d[i - 1][j - 1] + c2;//修改的代价
d[i][j] = Math.min(cost1, Math.min(cost2, cost3));
}
}
}
return d[n][m];
}
}
int dp[505][505];
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
// write code here
memset(dp, 0x3f, sizeof(dp));
dp[0][0] = 0;
c2 = min(c2, c0+c1); //修改 = 先删除后插入
for(int i=0; i<=n; i++)
for(int j=0; j<=m; j++){
int edit = A[i-1]!=B[j-1]? c2: 0;
if(j) dp[i][j] = min(dp[i][j], dp[i][j-1] + c0);
if(i) dp[i][j] = min(dp[i][j], dp[i-1][j] + c1);
if(i&&j)dp[i][j] = min(dp[i][j], dp[i-1][j-1] + edit);
}
return dp[n][m];
}
};
import java.util.*;
public class MinCost { public int findMinCost(String str1, int n, String str2, int m, int ic, int dc, int uc) { int [][]dp=new int [n+1][m+1];
//第一列表示str1到空串需要的代价所以是删除代价的倍数,
//第一行表示空串到str2需要的代价所以是添加代价的倍数
for(int i=1; i<=n ;i++)
dp[i][0]=i*dc;
for(int i=1; i<=m ;i++)
dp[0][i]=i*ic;
//dp[i][j]表示str1[0..i-1]变到str2[0..j-1]需要的最小代价
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]=dp[i-1][j-1]+uc;
}
//str1前面[0..i-2]的部分变成了str2[0..j-1],加一个删除代价
//str1[0..i-1]变成了str2前面的[0..j-2]部分,加一个添加代价
//然后取三个代价的最小值更新到dp[i][j]
dp[i][j]= Math.min(dp[i][j],dp[i][j-1]+ic);
dp[i][j]= Math.min(dp[i][j],dp[i-1][j]+dc);
}
}
return dp[n][m];
}
}
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
int dp[n+1][m+1];
dp[0][0] = 0;
for(int i=1;i<=n;i++)
dp[i][0] = dp[i-1][0] + c1;
for(int j=1;j<=m;j++)
dp[0][j] = dp[0][j-1] + c0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(A[i-1] == B[j-1])
dp[i][j] = dp[i-1][j-1];
else
dp[i][j] = min(dp[i-1][j-1]+c2, min(dp[i-1][j]+c1, dp[i][j-1]+c0)); } return dp[n][m];
}
};
package dp;
/**
最小编辑代价
题目描述:
对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,
定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。
保证两串长度均小于等于300,且三种代价值均小于等于100。
测试样例:
"abc",3,"adc",3,5,3,100
返回:8
思路:动态规划
*/
public class MinEditCost {
public int findMinCost(String str1, int m, String str2, int n, int ic, int dc, int rc) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int[][] dp = new int[m+1][n+1];
//第一行
for (int i = 0; i <= n; i++) {
dp[0][i] = i*ic;
}
//第一列
for (int i = 0; i <= m; i++) {
dp[i][0] = i*dc;
}
for (int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
if (s1[i-1] == s2[j-1]) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = dp[i-1][j-1] + rc;
}
dp[i][j] = Math.min(dp[i][j], dp[i-1][j]+dc);
dp[i][j] = Math.min(dp[i][j], dp[i][j-1]+ic);
}
}
return dp[m][n];
}
}
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int cr, int sc, int th) {
// write code here
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
dp[0][0] = 0;
for (size_t i = 1; i < m+1; i++)//第一行
{
dp[0][i] = i*cr;
}
for (size_t i = 1; i < n + 1; i++)//第一行
{
dp[i][0] = i*sc;
}
for (size_t i = 1; i < n+1; i++)
{
for (size_t j = 1; j < m+1; j++)
{
if (A[i-1]==B[j-1])
{
dp[i][j] = dp[i - 1][j - 1];
}
else
{
dp[i][j] = min(dp[i][j - 1] + cr, min(dp[i - 1][j] + sc, dp[i - 1][j - 1] + th));
}
}
}
return dp[n][m];
}
};
//动态规划, 只用了一维数组,节省内存
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int ic, int dc, int sc) {
// write code here
if(m==0) return dc*n;
if(n==0) return ic*m;
vector<int> dp(m+1,0); // dp[j] = dp[i][j]
for(int j=1;j<=m;j++) // init dp[0][0]
dp[j] = dp[j-1]+ic; // dp
int corner=0,minCost; // corner = dp[i-1][j-1]
for(int i=1;i<=n;i++){
dp[0] = dp[0]+dc; // dp[i][0] = dp[i-1][0]
for(int j=1;j<=m;j++){
if(A[i-1]==B[j-1])
minCost = corner;
else
minCost = corner+sc;
minCost = min(minCost,dp[j-1]+ic);// inserte B[i] dp[j-1] = dp[i][j-1]
minCost = min(minCost,dp[j]+dc) ; //delete A[i] dp[j]=dp[i-1][j]
corner = dp[j]; // update dp[i-1][j-1] -> dp[i-1][j]
dp[j] = minCost; //dp[j] = dp[i][j]
}
corner = dp[0]; // update corner -> dp[i][0]
}
return dp[m];
}
};
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
// write code here
//动态规划,利用dp[][]数组。
vector<vector<int> >dp(n+1,vector<int>(m+1,0));
for(int i=0;i<=m;i++)
dp[0][i]=i*c0;
for(int j=0;j<=n;j++)
dp[j][0]=j*c1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(A[i-1]==B[j-1]){
dp[i][j]=dp[i-1][j-1];
}else{
dp[i][j]=dp[i-1][j-1]+c2;
}
dp[i][j]=dp[i][j]>dp[i-1][j]+c1? dp[i-1][j]+c1:dp[i][j];
dp[i][j]=dp[i][j]>dp[i][j-1]+c0? dp[i][j-1]+c0:dp[i][j];
}
}
return dp[n][m];
}
};
import java.util.*;
//参考:http://blog.csdn.net/u014041033/article/details/51142331
public class MinCost {
//c0:插入;c1:删除;c2:修改
public int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
int[][] dp = new int[n+1][m+1]; //注:dp[i][j]代表从A[0..i],变为B[0..j]的最小代价!
//为了方便计算,第一行第一列添加空字符,A[0]=“” B[0]=“” dp[n+1][m+1]
//外边界初始化
for(int i=1; i<=n; i++){ //i从1-n,防止i-1越界
dp[i][0] = dp[i-1][0] + c1;
}
for(int i=1; i<=m; i++){
dp[0][i] = dp[0][i-1] + c0;
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(A.charAt(i-1) == B.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}else{
//取三种情况的代价最小值,因为一次只能比较两个值,所以调用两次
dp[i][j] = Math.min(dp[i-1][j-1]+c2, Math.min(dp[i-1][j]+c1, dp[i][j-1]+c0));
}
}
}
return dp[n][m];
}
}
import java.util.*;
public class MinCost {
public int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
int len=n>m?n:m;
/*d[i][j]表示字符串A的前i个字符构成的子串
和字符串B的前j个字符构成的子串的最短编辑距离
则d[n][m]为所求最终结果*/
int d[][]=new int[len+1][len+1];
c2=Math.min(c0+c1,c2);
/*边界条件*/
for(int i=0;i<=len;i++){
d[i][0]=i*c1;
}
for(int j=0;j<=len;j++){
d[0][j]=j*c0;
}
/*转移方程*/
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(A.charAt(i-1)==B.charAt(j-1)){
d[i][j]=d[i-1][j-1];
}else{
d[i][j]=min(d[i-1][j]+c1,/*删除*/
d[i][j-1]+c0,/*插入*/
d[i-1][j-1]+c2);/*修改*/
}
}
}
return d[n][m];
}
public int min(int a,int b,int c){
int t=a>b?b:a;
return t>c?c:t;
}
}
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
//f[i][j] represent the cost to edit A[i, n) to B[j, m)
vector<vector<int>> f(n+1, vector<int>(m+1));
//try to let A[n, n) to match B[m, m), just null to null
f[n][m] = 0;
for(int i = 0; i < n; ++i){
//try to let A[i, n) to match B[m, m), have to delete all
f[i][m] = (n-i) * c1;
}
for(int j = 0; j < m; ++j){
//try to let A[n, n) to match B[j, m), have to insert all
f[n][j] = (m-j) * c0;
}
for(int i = n-1; i > -1; --i){
for(int j = m-1; j > -1; --j){
if(A[i] == B[j]) f[i][j] = f[i+1][j+1];
else{
//try to let A[i+1,n) match B[j,m), operation is delete A[i]
f[i][j] = f[i+1][j] + c1;
//try to let A[i,n) match B[j+1,m), operation is insert B[j]
f[i][j] = min(f[i][j], f[i][j+1] + c0);
//try to make A[i] equal to B[j]
if(c0 + c1 < c2){
//better way is delete then insert
f[i][j] = min(f[i][j], f[i+1][j+1] + c0 + c1);
}
else{
//better way is replace A[i] by B[j]
f[i][j] = min(f[i][j], f[i+1][j+1] + c2);
}
}
}
}
return f[0][0];
}
};
/*
分析:
dp[i][j]代表用 str1[0~i-1]编辑乘str2[0~j-1]的最小代价
分析简单情况:
dp[0][j]:即把一个空串编辑乘str2[0~j-1]的代价则即将j个字符全部插入即
dp[0][j] = j*c0;
dp[i][0]:即把str1[0~i-1]编辑乘空串的代价,即将i个字符全部删除即
dp[i][0] = i*c1
dp[i][j]:分四种情况:
1) 先把str1[0~i-1]编辑成str1[0~i-2],在把str1[0~i-2]编辑成str2[0~j-1]
dp[i][j] = dp[i-1][j] + c1;
2) 先把str1[0~i-1]编辑成str2[0~j-2],在把str2[0~j-2]编辑成str2[0~j-1]
dp[i][j] = dp[i][j-1] + c0;
3) 如果str1[i-1] != str2[j-1],则可以先将str1[0~i-2]编辑成str2[0~j-2],然后进行替换
dp[i][j] = dp[i-1][j-1] + c2;
4) 如果str1[i-1] == str2[j-1],则直接将str1[0~i-2]编辑成str2[0~j-2]
dp[i][j] = dp[i-1][j-1]
从以上情况中选择代价最小的一种情况
*/
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2)
{
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
//初始化dp[0][j]
for (int j = 0; j <= m; j++)
{
dp[0][j] = j*c0;
}
//初始化dp[i][0]
for (int i = 0;i <= n; i++)
{
dp[i][0] = i*c1;
}
//其他情况
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
dp[i][j] = min(dp[i-1][j] + c1, dp[i][j-1] + c0);
if (A[i-1] == B[j-1])
dp[i][j] = min(dp[i-1][j-1], dp[i][j]);
else
dp[i][j] = min(dp[i-1][j-1] + c2, dp[i][j]);
}
}
return dp[n][m];
} class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
// write code here
vector<vector<int> >dp(n+2, vector<int>(m+2));
for(int i=0;i<=n; i++){
for(int j=0; j<=m; j++){
if(j==0) dp[i][j] = i*c1;//A->0 delete
else if(i==0) dp[i][j] = j*c0;
else{
int cost = A[i-1]==B[j-1]?0:1;//注意一下字符串下标是从0开始的
int a = dp[i-1][j] + c1;// i-1->j delete i
int b = dp[i][j-1] + c0;// i->j-1 insert j
int c = dp[i-1][j-1] + cost*c2;
dp[i][j] = min(a, min(b,c));
}
}
}
return dp[n][m];
}
}; classMinCost {public:intfindMinCost(string A, intn, string B, intm, intc0, intc1, intc2) {vector<int>dp(B.size() + 1, 0);for(intj = 0; j <= B.size(); ++j){dp[j] = c0*j;}for(inti = 1; i <= A.size(); ++i){ //左上角的值int pre = dp[0];dp[0] = c1*i;for(intj = 1; j <= B.size(); ++j){ //正上方的值int tmp = dp[j];if(A[i - 1] == B[j - 1])dp[j] = pre;else dp[j] = pre + c2;dp[j] = min(dp[j], dp[j - 1] + c0);dp[j] = min(dp[j], tmp + c1);pre = tmp;}}return dp[B.size()];}};
class MinCost {
public:
int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2) {
int iValue = c0;
int dValue = c1;
int mValue = c2;
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++) {
dp[i][0] = dValue * i;
}
for (int i = 1; i <= m; i++) {
dp[0][i] = iValue * i;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A[i - 1] == B[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
// modify cost
int modifyCost = dp[i - 1][j - 1] + mValue;
// insert cost
int insertCost = dp[i][j - 1] + iValue;
// delete cost
int deleteCost = dp[i - 1][j] + dValue;
dp[i][j] = min(modifyCost, min(insertCost, deleteCost));
}
}
}
return dp[n][m];
}
};
# -*- coding:utf-8 -*- #分析: #dp[i][j]代表用 str1[0~i-1]编辑乘str2[0~j-1]的最小代价 #分析简单情况: #dp[0][j]:即把一个空串编辑乘str2[0~j-1]的代价则即将j个字符全部插入即 #dp[0][j] = j*c0; #dp[i][0]:即把str1[0~i-1]编辑乘空串的代价,即将i个字符全部删除即 #dp[i][0] = i*c1 #dp[i][j]:分四种情况: #1) 先把str1[0~i-1]编辑成str1[0~i-2],在把str1[0~i-2]编辑成str2[0~j-1] #dp[i][j] = dp[i-1][j] + c1; #2) 先把str1[0~i-1]编辑成str2[0~j-2],在把str2[0~j-2]编辑成str2[0~j-1] #dp[i][j] = dp[i][j-1] + c0; #3) 如果str1[i-1] != str2[j-1],则可以先将str1[0~i-2]编辑成str2[0~j-2],然后进行替换 #dp[i][j] = dp[i-1][j-1] + c2; #4) 如果str1[i-1] == str2[j-1],则直接将str1[0~i-2]编辑成str2[0~j-2] #dp[i][j] = dp[i-1][j-1] #从以上情况中选择代价最小的一种情况 class MinCost: def findMinCost(self, A, n, B, m, c0, c1, c2): dp=[[0 for i in range(m+1)]for i in range(n+1)] for i in range(n+1):#初始化dp[0][j] dp[i][0]=i*c1 for j in range(m+1):#初始化dp[i][0] dp[0][j]=j*c0 for i in range(1,n+1):#其他情况 for j in range(1,m+1): dp[i][j]=min(dp[i-1][j]+c1,dp[i][j-1]+c0) if A[i-1]==B[j-1]: dp[i][j]=min(dp[i-1][j-1],dp[i][j]) else: dp[i][j]=min(dp[i-1][j-1]+c2,dp[i][j]) return dp[n][m]
/*
* 参考上面大神的解题思路
* */
public class MinCost {
// dp[i][j] 表示将长为i的字符串n转换成长为j的字符串m需要的代价
public int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
// 初始化的时候需要特殊处理
int[][] dp = new int[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
// 不断删除
dp[i][0] = dp[i - 1][0] + c1;
}
for (int i = 1; i <= m; i++) {
// 不断插入
dp[0][i] = dp[0][i - 1] + c0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (A.charAt(i - 1) == B.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
/*
* 调整的时候有三种情况,
* 修改:dp[i-1][j-1]基础上修改
* 插入:dp[i][j-1]基础上往m中插入一个字符
* 删除:dp[i-1][j],i-1长度的n已经转变成j长度的m,那么只需要删除一个字符就可以
* */
} else {
dp[i][j] = Math.min(dp[i - 1][j] + c0, Math.min(dp[i][j - 1] + c1, dp[i - 1][j - 1] + c2));
}
}
}
return dp[n][m];
}
}
动态规划问题只不过将代价都为1变成了指定的,注意初始化以及状态方程即可:
import java.util.*;
public class MinCost {
public static int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
// write code here
int[][] dis=new int[n+1][m+1];
for(int i=0;i<=n;i++) {
dis[i][0]=i*c1;
}
for(int j=0;j<=m;j++) {
dis[0][j]=j*c0;
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
dis[i][j]=Math.min(dis[i][j-1]+c0, Math.min(dis[i-1][j]+c1,dis[i-1][j-1]+(A.charAt(i-1)==B.charAt(j-1)?0:c2 )));
}
}
return dis[n][m];
}
}
public static int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) { // write code here /* 当A=="" 或者B==""时,cost是删除或插入的代价 当A!="" 且 B!= ""时 A[i] == B[j] D[i][j] = D[i-1][j-1] A[i] != B[j] D[i][j] = MIN{D[i-1][j-1]+c2(修改一个值),D[i-1][j]+c1(删除一个值),D[i][j-1]+c0(插入一个值)} */ int[][] D = new int[n+1][m+1]; for(int i = 1; i < n + 1;i ++){ D[i][0] = D[i-1][0] + c1; } for(int j = 1; j < m + 1 ; j ++){ D[0][j] = D[0][j-1] + c0; } for(int i = 1; i < n + 1; i ++){ for(int j = 1; j < m + 1 ; j ++){ if (A.charAt(i - 1) == B.charAt(j - 1)) { D[i][j] = D[i - 1][j - 1]; } else { D[i][j] = Math.min(D[i - 1][j - 1] + c2, Math.min(D[i][j - 1] + c0, D[i - 1][j] + c1)); } } } return D[n][m]; }