动态规划之字符串最短编辑距离

题目描述

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

  1. 删除–将字符串A中的某个字符删除。

  2. 插入–在字符串A的某个位置插入某个字符。

  3. 替换–将字符串A中的某个字符替换为另一个字符。

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

输入格式

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

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

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

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

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

输出格式

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

数据范围

1≤n,m≤1000

输入样例:

10
AGTCTGACGC
11
AGTAAGTAGGC

输出样例:

4

题解:

将一个字符串通过删除、插入、替换变为另一个字符串的最短距离,可以用动态规划来做,用f(i, j)来表示长度为i的字符串变为长度为j的字符串最小的操作次数,那么如何来求f(i, j)呢?对每个字符我们有3种操作:

1.删除:假设删除a[i]后,a[1 ~ i] 与 b[1 ~ j] 匹配,那么说明a[1 ~ i - 1]已经与b[1 ~ j]相等了,那么多出来的a[i]直接删掉即可,状态转移方程为:f(i, j) = f(i - 1, j) + 1

2.插入: 假设插入一个a[i],使a[i] == b[j]后,a[1 ~ i] 与 b[1 ~ j] 匹配,那么说明a[1 ~ i]已经与b[i ~ j - 1]相等了,要使a[1 ~ i]与b[i ~ j]相等,只需再a[1 ~ i]的后面添加一个b[j]即可

状态转移方程为:f(i, j) = f(i, j - 1) + 1

3.替换:假设将a[i]替换成b[j],使得a[1 ~ i] 与 b[1 ~ j] 匹配,那么说明a[1 ~ i - 1]已经与b[i ~ j - 1]相等了,要使a[1 ~ i]与b[i ~ j]相等,只需将a[i]替换为b[j]即可。

如果a[i] = b[j],则无需替换,状态转移方程为:f(i, j) = f(i - 1, j - 1)

如果a[i] != b[j],则需要替换,状态转移方程为:f(i, j) = f(i - 1, j - 1) + 1

所以我们得出来总的状态转移方程式为就是上述方程式的最小值

代码如下:

#include
using namespace std;
const int N = 1010;
char s1[N], s2[N];
int f[N][N];
int main()
{
    int n, m;
    cin >> n >> s1 + 1;
    cin >> m >> s2 + 1;
    for(int i = 0; i <= n; i++)  //a[i ~ i]变为0,只能删除, 操作数为i
        f[i][0] = i;
    for(int i = 0; i <= m; i++)//a[0]变为b[1 ~ i],只能添加,操作数为i
        f[0][i] = i;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            //f[i - 1][j] + 1 表示进行删除操作
            //f[i][j - 1] + 1 表示进行添加操作
            f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
            //下面的表示进行替换操作
            if(s1[i] == s2[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;
}

你可能感兴趣的:(动态规划)