“文本比对基础:最短编辑距离算法的原理与实现“

最短编辑距离

给定两个字符串 𝐴 和 𝐵,现在要将 𝐴 经过若干操作变为 𝐵,可进行的操作有:

  1. 删除--将字符串 𝐴 中的某个字符删除。
  2. 插入--在字符串 𝐴 的某个位置插入某个字符。
  3. 替换--将字符串 𝐴 中的某个字符替换为另一个字符。

现在请你求出,将 𝐴 变为 𝐵 至少需要进行多少次操作。

输入格式

第一行包含整数 𝑛,表示字符串 𝐴 的长度。

第二行包含一个长度为 𝑛 的字符串 𝐴。

第三行包含整数 𝑚,表示字符串 𝐵 的长度。

第四行包含一个长度为 𝑚 的字符串 𝐵。

字符串中均只包含大小写字母。

输出格式

输出一个整数,表示最少操作次数。

数据范围

1≤𝑛,𝑚≤1000

输入样例:
复制代码
10
AGTCTGACGC
11
AGTAAGTAGGC
输出样例:
复制代码
4

1.状态表示 :fij

集合:将a1\~i 变成 b1\~j的操作方式

属性:min

2.状态计算 :从最后一步考虑

有三种操作,所以有三个子集

ok子集划分完了

考虑状态转移的时候

先考虑如果我没有进行这个操作应该是什么状态

然后考虑你进行这一步操作之后会对你下一个状态造成什么影响

然后再加上之前状态表示中你决策出来的那个DP属性

这样就可以自然而然地搞出来转移方程啦

1)删除操作:把ai删掉之后a1~i和b1~j匹配

所以之前要先做到a1~(i-1)和b1~j匹配

fi-1j + 1

2)插入操作:插入之后ai与bj完全匹配,所以插入的就是bj

那填之前a1~i和b1~(j-1)匹配

fij-1 + 1

3)替换操作:把ai改成bj之后想要a1~i与b1~j匹配

那么修改这一位之前,a1~(i-1)应该与b1~(j-1)匹配

fi-1j-1 + 1

但是如果本来ai与bj这一位上就相等,那么不用改,即

fi-1j-1 + 0

好的那么fij就由以上三个可能状态转移过来,取个min
细节问题:初始化怎么搞

先考虑有哪些初始化嘛

1.你看看在for遍历的时候需要用到的但是你事先没有的

(往往就是什么0啊1啊之类的)就要预处理

2.如果要找min的话别忘了INF

要找有负数的max的话别忘了-INF

ok对应的:

1.f0i如果a初始长度就是0,那么只能用插入操作让它变成b

fi0同样地,如果b的长度是0,那么a只能用删除操作让它变成b

2.fij = INF //虽说这里没有用到,但是把考虑到的边界都写上还是保险

思路:

f[i][j]表示第一个字符串的前 i 个字母变为第二个字符串的前 j 个字母所用的最少操作次数。

假设第一个字符串为:AGTCTGACGC

第二个字符串为:AGTAAGTAGGC

f[3][5] 表示把第一个字符串的前三个字母变为第二个字符串的前五个字母所需要的最少操作次数。

也就是把AGT变为AGTAA所用的最少操作次数。

分析递推方程:

把第一个字符串的前 i 个字母变为第二个字符串的前 j 个字母,有三种方法:

  • 把第一个字符串的前 i 个字母变为第二个字符串的前 j - 1 个字符,然后在第一个字符串后面增加第二个字符串的第j个字母。

    这种情况下,f[i][j] = f[i][j - 1] + 1

    例如:把AGT变为AGTAA,可以先把AGT变为AGTA,然后再在最后面添加一个字符A。

  • 把第一个字符串的前 i - 1 个字母变为第二个字符串的前 j 个字符,然后去掉最后一个字符。

​ 例如:把AGT变为AGTAA,可以先把AGT变为AGTAAT,然后再去掉一个字符T。

​ 这种情况下,f[i][j] = f[i - 1][j] + 1

  • 把第一个字符串的前 i - 1 个字母变为第二个字符串的前 j - 1个字符。变化之后,对比最后一个字符,如果相等,则变换完成,如果不同,把第一个字符串的最后一个字符变为第二个字符串的最后一个字符,

    例如:把AGT变为AGTAA,可以先把AGT变为AGTAT,然后再在最后面添加一个字符T变为A。

    例如:把AGT变为AGTAT,可以先把AGT变为AGTAT,因为最后一个字符相同,不再做处理。

    这种情况下,f[i][j] = f[i - 1][j - 1] + 1(最一个字符不同) 或f[i][j] = f[i - 1][j + 1] (最一个字符相同)。

取三种情况的最小值,就是f[i][j]

时间复杂度:O(n^2)。

代码:

cpp 复制代码
#include <iostream>
using namespace std;
const int N = 1010;

char a[N], b[N];//分别存放两个字符串
int f[N][N];//存储结果

int n, m;//两个字符串的长度

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];

    cin >> m;
    for(int i = 1; i <= m; i++) cin >> b[i];
    //边界,a 字符串的前 i 个字符变为 b 字符串的前 0 个字符,需要 i 步
    for(int i = 0; i <= n; i++) f[i][0] = i;
    //边界,a 字符串的前 0 个字符变为 b 字符串的前 i 个字符,需要 i 步
    for(int i = 0; i <= m; i++) f[0][i] = i;
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <=m; j++)
        {
            //情况一 二
            f[i][j] = min(f[i][j - 1] + 1, f[i - 1][j] + 1);
            //情况三
            if(a[i] != b[j]) f[i][j] = min(f[i][j], f[i - 1][j - 1] + 1);
            else f[i][j] = min(f[i][j], f[i - 1][j - 1]);
        }
    }
    //f[n][m] 表示 a 字符传递额前 n 个字符变为 b 字符传递额前 m 个字符需要的最少步骤。
    cout << f[n][m];

}
相关推荐
一次旅行17 分钟前
AutoAWQ完整实战:MIT激活感知AWQ量化,模型显存减半、推理提速且精度无损
人工智能·python·算法
GrowthDiary00737 分钟前
算法题:寻找二维数组top k问题
数据结构·python·算法
可编程芯片开发43 分钟前
基于全阶观测器的三自由度运动系统状态反馈控制simulink建模与仿真
算法
kobesdu43 分钟前
从零推导FAST-LIO的观测雅可比矩阵
人工智能·算法·矩阵
乐思智能科技有限公司1 小时前
PLECS软件学习使用(二)直流电机基本系统模型
人工智能·算法·机器学习·面试·职场和发展
随意起个昵称1 小时前
贪心模型-Johnson法则
c++·算法
旋生万物2 小时前
电磁力 = 螺旋联络的 90° 旋转?麦克斯韦方程组的几何重构
人工智能·python·算法·机器学习·copilot·世界模型·物理ai
余俊晖2 小时前
多模态大模型细粒度视觉理解:Vision-OPD在线策略自蒸馏技术方案概述
人工智能·深度学习·算法·多模态·opd
脚踏实地皮皮晨2 小时前
003003001_Grid控件
开发语言·windows·算法·c#·visual studio
Hi李耶3 小时前
【LeetCode】6-Z字形变换
算法·leetcode·职场和发展