跳转至

动态规划 编辑距离

前置知识

最长公共子序列

目标

掌握例题代码

edit distance编辑距离

aka, Levenshtein distance莱文斯坦距离(aka, also known as)

举例

字符串A("xyzab")和字符串B("axyzc"),问至少经过多少步操作可以把A变成B。

我们还是从两个字符串的最后一个字符来考察即'b'和'c'。显然二者不相同,那么我们有以下三种处理办法:

(1)增加:在A末尾增加一个'c',那么A变成了"xyzabc",B仍然是"axyzc",由于此时末尾字符相同了,
那么就变成了比较"xyzab"和"axyz"的距离,即d(xyzab,axyzc) = d(xyzab,axyz) + 1

可以写成d(i,j) = d(i,j-1) + 1。表示下次比较的字符串B的长度减少了1,而加1表示当前进行了一次字符的操作

(2)删除:删除A末尾的字符'b',考察A剩下的部分与B的距离。即d(xyzab,axyzc) = d(xyza,axyzc) + 1

可以写成d(i,j) = d(i-1,j) + 1。表示下次比较的字符串A的长度减少了1

(3)替换:把A末尾的字符替换成'c',这样就与B的末尾字符一样了,那么接下来就要考察出了末尾'c'部分的字符,
即d(xyzab,axyzc) = d(xyza,axyz) + 1

写成d(i,j) = d(i-1,j-1) + 1表示字符串A和B的长度均减少了1

例题,1276:【例9.20】编辑距离

// 示例代码
// 编辑距离的问题,和LCS很像很像
// 放在一块进行对比学习,更有帮助
#include <bits/stdc++.h>

using namespace std;

const int N = 2010;

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

int main()
{
    scanf("%s%s", a + 1, b + 1);
    n = strlen(a + 1), m = strlen(b + 1);

    // 初始化
    dp[0][0] = 0;
    for (int i = 1; i <= n; i++) dp[i][0] = i;
    for (int j = 1; j <= m; j++) dp[0][j] = j;

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++){
            dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; 

            if (a[i] == b[j]) dp[i][j] = min(dp[i][j], dp[i-1][j-1]);
        }

    cout << dp[n][m] << '\n';

    return 0;
}

参考

https://www.jianshu.com/p/12e9b9a9a