最短编辑距离

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

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

1.状态表示 :f[i][j] 代表a字符串前i个字符替换成b字符串前j个的最小操作

集合:将a[1i]变成b[1j]的操作方式
属性:min

2.状态计算

有三种操作,所以有三个子集
考虑状态转移的时候
先考虑如果我没有进行这个操作应该是什么状态
然后考虑你进行这一步操作之后会对你下一个状态造成什么影响
然后再加上之前状态表示中你决策出来的那个DP属性

1)删除操作:把a[i]删掉之后a[1i]和b[1j]匹配
所以之前要先做到a[1(i-1)]和b[1j]匹配
f[i-1][j] + 1
2)插入操作:插入之后a[i]与b[j]完全匹配,所以插入的就是b[j]
那填之前a[1i]和b[1(j-1)]匹配
f[i][j-1] + 1
3)替换操作:把a[i]改成b[j]之后想要a[1i]与b[1j]匹配
那么修改这一位之前,a[1(i-1)]应该与b[1(j-1)]匹配
f[i-1][j-1] + 1
但是如果本来a[i]与b[j]这一位上就相等,那么不用改,即
f[i-1][j-1] + 0

f[i][j]就由以上三个可能状态转移过来,取个min

初始化问题

f[0][i]如果a初始长度就是0,那么只能用插入操作让它变成b
f[i][0]同样地,如果b的长度是0,那么a只能用删除操作让它变成b
code:

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

using namespace std;

const int N = 1e3 + 10;

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

int main(){
    int n, m;
    cin >> n >> a + 1;
    cin >> m >> b + 1;
     // f[i][0]同样地,如果b的长度是0,那么a只能用删除操作让它变成b
    for (int i = 0; i <= n; i ++) 
        f[i][0] = i;
    // f[0][i]如果a初始长度就是0,那么只能用插入操作让它变成b
    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 - 1][j] + 1, f[i][j - 1] + 1);
            // f[i][j]继承的上一步操作,所以后续判断不能直接让f[i][j] = f[i - 1][j - 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];
    return 0;
}
posted @ 2021-11-18 23:09  Gsding  阅读(34)  评论(0)    收藏  举报