编辑距离——线性DP(C++)

定义

编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。一般来说,编辑距离越小,两个串的相似度越大。
推荐题解baodream

经典例题

AcWing 902. 最短编辑距离
给定两个字符串A和B,现在要将A经过若干操作变为B,可进行的操作有:

删除–将字符串A中的某个字符删除。
插入–在字符串A的某个位置插入某个字符。
替换–将字符串A中的某个字符替换为另一个字符。
现在请你求出,将A变为B至少需要进行多少次操作。

输入格式
第一行包含整数n,表示字符串A的长度。

第二行包含一个长度为n的字符串A。

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

第四行包含一个长度为m的字符串B。

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

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

数据范围
1≤n,m≤1000
输入样例:

10 
AGTCTGACGC
11 
AGTAAGTAGGC

输出样例:

4

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;
char a[N], b[N];
int f[N][N];//f[i][j] 表示 a[1-i]变化到b[1-j]最小的变化次数

int main()
{
    
    
    scanf("%d%s", &n, a + 1);
    scanf("%d%s", &m, b + 1);
    //首先初始化  f[i][0] f[j][0] 
    //f[0][j] 若b为j长度 a为0 则a需要增加j次才能变成b
    //f[i][0] 若a为i长度 b为0 则a需要删除i次才能编程b
    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);
        }

    printf("%d\n", f[n][m]);

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/62472/

AcWing 899. 编辑距离
给定n个长度不超过10的字符串以及m次询问,每次询问给出一个字符串和一个操作次数上限。

对于每次询问,请你求出给定的n个字符串中有多少个字符串可以在上限操作次数内经过操作变成询问给出的字符串。

每个对字符串进行的单个字符的插入、删除或替换算作一次操作。

输入格式
第一行包含两个整数n和m。

接下来n行,每行包含一个字符串,表示给定的字符串。

再接下来m行,每行包含一个字符串和一个整数,表示一次询问。

字符串中只包含小写字母,且长度均不超过10。

输出格式
输出共m行,每行输出一个整数作为结果,表示一次询问中满足条件的字符串个数。

数据范围
1≤n,m≤1000,

输入样例:

3 2
abc
acd
bcd
ab 1
acbd 2

输出样例:

1
3
1.str1或str2的长度为0返回另一个字符串的长度。 if(str1.length0) return str2.length; if(str2.length0) return str1.length;
2.初始化(n+1)(m+1)的矩阵d,并让第一行和列的值从0开始增长。扫描两字符串(nm级的),如果:str1[i] == str2[j],用temp记录它,为0。否则temp记为1。然后在矩阵d[i,j]赋于d[i-1,j]+1 、d[i,j-1]+1、d[i-1,j-1]+temp三者的最小值。
3.扫描完后,返回矩阵的最后一个值d[n][m]即是它们的距离。

举例子:字符串“ivan1”和“ivan2”
1.第一行和第一列的值从0开始增长
注意,我们先给数列的第一行第一列赋值,从0开始递增赋值。我们就得到了图一的这个样子
图一
计算规则就是:
d[i,j]=min(d[i-1,j]+1 、d[i,j-1]+1、d[i-1,j-1]+temp) 这三个当中的最小值。
其中:str1[i] == str2[j],用temp记录它,为0。否则temp记为1

我们用d[i-1,j]+1表示增加操作
d[i,j-1]+1 表示我们的删除操作
d[i-1,j-1]+temp表示我们的替换操作

2、举证元素的产生 Matrix[i - 1, j] + 1 ; Matrix[i, j - 1] + 1 ; Matrix[i - 1, j - 1] + t 三者当中的最小值

在这里插入图片描述
3.依次类推直到矩阵全部生成
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;

const int N = 15, M = 1010;

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()
{
    
    
    scanf("%d%d", &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 ++ ;

        printf("%d\n", res);
    }

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/62479/

猜你喜欢

转载自blog.csdn.net/Annabel_CM/article/details/110407347