[线性dp] 编辑距离(模板题+编辑距离模型)

8 篇文章 0 订阅

0. 前言

编辑距离:很类似于 LCS 问题,状态表示十分类似。学习 dp 问题必备入门题了

1. 编辑距离模板题

902. 最短编辑距离
在这里插入图片描述

重点: 线性 dpLCS 问题及优化

思路:

  • 状态定义:
    • f[i][j] 所有将 a[1:i] 变成 b[1:j] 的操作次数的最小值
  • 状态转移:
    • 分类依据:分别三种方式操作 a 中的第 i 个字母,使得,a[1:i]b[1:j] 匹配
      • 删除 a 的第 i 个字母,使得 a[1:i]b[1:j] 匹配,等价于 f[i-1][j] + 1,因为 a[1:i-1] == b[1:j]
      • 增加 a 的第 i 个字母,使得 a[1:i]b[1:j] 匹配,等价 f[i][j-1] + 1,因为 a[1:i] == b[1:j-1]
      • 修改 a 的第 i 个字母,使得 a[1:i]b[1:j] 匹配,等价 f[i-1][j-1]+1/0,如果 a[i] == b[j] 则不需要再修改,如果 a[i] != b[j] 则说明 a[1:a-1] == b[1:j-1],则一步操作就能改过来,所以 +1
  • 边界处理及初始化
    • f[i][0] 需要把第一个字符串连续删 i 次才能和 b 相等,即,f[i][0] = i
    • f[0][i] 需要把第二个字符串连续删 i 次才能和 a 相等,即,f[0][i] = i
    • 时间复杂度:
    • O ( n 2 ) O(n^2) O(n2)

代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1005;

int n, m;
char a[N], b[N];
int f[N][N];

int main() {
    scanf("%d%s", &n, a + 1);
    scanf("%d%s", &m, b + 1);
    
    for (int i = 0; i <= m; ++i) f[0][i] = i;
    for (int i = 0; i <= n; ++i) f[i][0] = i;
    
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
            if (a[i] == b[j]) f[i][j] = min(f[i][j], f[i - 1][j - 1]);
            else f[i][j] = min(f[i][j], f[i - 1][j - 1] + 1);
        }
    }
    cout << f[n][m] << endl;
    return 0;
}

经典编辑距离问题的变种题

899. 编辑距离

在这里插入图片描述
重点: 线性 dp、编辑距离问题变种

思路:

  • 问题解释:
    • 给了 n 个固定的字符串,然后再给定一个字符串,后面跟一个数字,是从固定字符串通过编辑,和本串相等的最大的编辑次数限制。让返回 n 个固定的字符串中在限制步数中能变成给定串的个数。
  • 时间复杂度:
    • 总共编辑距离需要做 1000 ( n ) ∗ 1000 ( m ) ∗ 100 ( 编 辑 距 离 为 10 ∗ 10 ) = 1 e 8 1000(n) * 1000(m) * 100(编辑距离为10*10)= 1e8 1000(n)1000(m)100(1010)=1e8 次计算,差不多能过,一般 C++ 一秒可求解 1e7~1e8 的计算量

状态定义及转移、初始化均与上面的编辑距离一样,不再赘述。

代码:

#include <iostream>
#include <algorithm>
#include <cstring>


using namespace std;

const int N = 15, M = 1005;

int n, m;
int f[N][N];
char str[M][N];

int edit_distance(char a[], char b[]) {
    int la = strlen(a + 1), lb = strlen(b + 1);
    
    for (int i = 0; i <= lb; ++i) f[0][i] = i;
    for (int i = 0; i <= la; ++i) f[i][0] = i;
    
    for (int i = 1; i <= la; ++i)
        for (int j = 1; j <= lb; ++j) {
            f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
            f[i][j] = min(f[i][j], f[i - 1][j - 1] + (a[i] != b[j]));
        }
        
    return f[la][lb];
}

int main() {
    cin >> n >> m;
    
    for (int i =  0; i < n; ++i) scanf("%s", str[i] + 1);
    
    while (m --) {
        char s[N];
        int limit;
        scanf("%s%d", s + 1, &limit);
        
        int res = 0;
        for (int i = 0; i < n; ++i)
            if (edit_distance(str[i], s) <= limit)
                res ++;
        cout << res << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值