最小编辑代价

最小编辑代价

题目描述

给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。

输入描述:

输出三行,第一行和第二行均为一行字符串,分别表示两个字符串str1,str2。 ( 1 ≤ l e n g t h ( s t r 1 ) , l e n g t h ( s t r 2 ) ≤ 5000 ) \left( 1\leq length(str1),length(str2) \leq 5000 \right) (1length(str1),length(str2)5000)。第三行为三个正整数,代表ic,dc和rc。(1<=ic<=10000、1<=dc<=10000、1<=rc<=10000)

输出描述:

输出一个整数,表示编辑的最小代价。

示例1
输入
abc
adc
5 3 2
输出
2
示例2
输入
abc
adc
5 3 100
输出
8
示例3
输入
abc
abc
5 3 2
输出
0
备注:

时间复杂度 O ( n ∗ m ) O(n*m) O(nm) ,空间复杂度 O ( n ) O(n) O(n) 。(n,m代表两个字符串长度)


题解:

普通解法:

明显需要使用二维状态表,假设为:F[i, j],表示 str1[0…i] 转换成 str2[0…j] 的最小代价,则 F[i, j] 可以来自以下三个状态:

  • F [ i − 1 , j − 1 ] F[i-1, j-1] F[i1,j1] :如果 s t r 1 [ i ] = s t r 2 [ j ] str1[i] = str2[j] str1[i]=str2[j],则 F [ i , j ] = F [ i − 1 , j − 1 ] F[i, j] = F[i - 1, j - 1] F[i,j]=F[i1,j1];否则的话,可以对 s t r 1 [ i ] str1[i] str1[i] 位置进行替换,则 F [ i , j ] = F [ i − 1 , j − 1 ] + r c F[i, j]= F[i-1, j-1] + rc F[i,j]=F[i1,j1]+rc
  • F [ i − 1 , j ] F[i-1, j] F[i1,j]:表示删除 s t r 1 [ i ] str1[i] str1[i] 元素,则 F [ i , j ] = F [ i − 1 , j ] + d c F[i, j] = F[i-1, j] + dc F[i,j]=F[i1,j]+dc
  • F [ i , j − 1 ] F[i, j-1] F[i,j1]:表示插入 s t r 2 [ j ] str2[j] str2[j] 元素,则 F [ i , j ] = F [ i , j − 1 ] + i c F[i, j] = F[i, j-1] + ic F[i,j]=F[i,j1]+ic

上面几个状态取最小值即可。

普通解法代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 5010;

int f[N][N];
char str1[N];
char str2[N];
int ic, dc, rc;

int main(void) {
    scanf("%s", str1);
    scanf("%s", str2);
    scanf("%d%d%d", &ic, &dc, &rc);
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    for (int i = 1; i <= len2; ++i) f[0][i] = i * ic;
    for (int j = 1; j <= len1; ++j) f[j][0] = j * dc;
    for (int i = 1; i <= len1; ++i) {
        for (int j = 1; j <= len2; ++j) {
            if (str1[i - 1] == str2[j - 1]) f[i][j] = f[i - 1][j - 1];
            else f[i][j] = f[i - 1][j - 1] + rc;
            f[i][j] = min(f[i][j], min(f[i - 1][j] + dc, f[i][j - 1] + ic));
        }
    }
    printf("%d\n", f[len1][len2]);
    return 0;
}

进阶解法:

题目要求额外空间为 O ( n ) O(n) O(n),所以,我们需要压缩上述二维状态表,一般方法是使用滚动数组。

我们看到,F[i, j] 跟 F[i-1, j-1]、F[i-1, j]、F[i, j-1] 有关,那么我们可以从左往右遍历。因为需要用到 F[i-1, j-1] 的值,所以我们需要额外保存上一轮的值。(此题是个不错的锻炼使用滚动数组的题目)

进阶解法代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 5010;

int f[N];
char str1[N];
char str2[N];
int ic, dc, rc;

int main(void) {
    scanf("%s", str1);
    scanf("%s", str2);
    scanf("%d%d%d", &ic, &dc, &rc);
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    for (int i = 1; i <= len2; ++i) f[i] = i * ic;
    for (int i = 1; i <= len1; ++i) {
        int lu = f[0];
        f[0] = i * dc;
        for (int j = 1; j <= len2; ++j) {
            int ans = f[j];
            if (str1[i - 1] == str2[j - 1]) f[j] = lu;
            else f[j] = lu + rc;
            f[j] = min(f[j], min(ans + dc, f[j - 1] + ic));
            lu = ans;
        }
    }
    printf("%d\n", f[len2]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值