一,题目
# 编辑距离
## 题目描述
设 $A$ 和 $B$ 是两个字符串。我们要用最少的字符操作次数,将字符串 $A$ 转换为字符串 $B$。这里所说的字符操作共有三种:
1. 删除一个字符;
2. 插入一个字符;
3. 将一个字符改为另一个字符。
$A, B$ 均只包含小写字母。
## 输入格式
第一行为字符串 $A$;第二行为字符串 $B$;字符串 $A, B$ 的长度均小于 $2000$。
## 输出格式
只有一个正整数,为最少字符操作次数。
## 样例 #1
### 样例输入 #1
```
sfdqxbw
gfdgw
```
### 样例输出 #1
```
4
```
## 提示
对于 $100 \%$ 的数据,$1 \le |A|, |B| \le 2000$。
链接:P2758 编辑距离 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
二,思路建立一个编辑距离的转化矩阵dp,dp[i][j]代表字符串A的前i个字符串转字符串B前j个字符串所需要的最少步骤。
以sfdqxbw和gfdgw(注:s是sfdqxbw第一个字符串,不是第0个)为例子,下面是该矩阵表示含义:
B\A | i=0 | i=1 | i=2 | i=3 | i=4 | i=5 | i=6 | i=7 |
j=0 | / | /s | /sf | /sfd | /sfdq | /sfdqx | /sfdqxb | /sfdqxbw |
j=1 | g/ | g/s | g/sf | g/sfd | g/sfdq | g/sfdqx | g/sfdqxb | g/sfdqxbw |
j=2 | gf/ | gf/s | gf/sf | gf/sfd | gf/sfdq | gf/sfdqx | gf/sfdqxb | gf/sfdqxbw |
j=3 | gfd/ | gfd/s | gfd/sf | gfd/sfd | gfd/sfdq | gfd/sfdqx | gfd/sfdqxb | gfd/sfdqxbw |
j=4 | gfdg/ | gfdg/s | gfdg/sf | gfdg/sfd | gfdg/sfdq | gfdg/sfdqx | gfdg/sfdqxb | gfdg/sfdqxbw |
j=5 | gfdgw/ | gfdgw/s | gfdgw/sf | gfdgw/sfd | gfdgw/sfdq | gfdgw/sfdqx | gfdgw/sfdqxb | gfdgw/sfdqxbw |
对于i=0,j=0,都是空字符串,所以dp[0][0]=0;
对于i=0,j=1,B为g,A为空,把g插入A中可得B,所以dp[0][1]=1;
对于i=0,j=2,B=gf,A为空,把g和f插入A中可得B,所以dp[0][2]=2;
对于i=0,j=3,B=gfd,A为空,把g,f,d插入A中可得B,所以dp[0][3]=3;
对于i=0;j=4,B=gfdg,A为空,把gfdg插入A中可得B,所以dp[0][4]=4;
对于i=0,j=5,B=gfdgw,A为空,把gfdgw插入A中可得B,所以dp[0][5]=5;
对于j等于0的情况也是如此
所以dp[1][0]=1,dp[2][0]=2,dp[3][0]=3,dp[4][0]=4,dp[5][0]=5,dp[6][0]=6,dp[7][0]=7;
此时讨论对于i=1的情况
对于i=1,j=0,B为空,A为s,把s插入B中可得B,所以dp[1][0]=1;
对于i=1,j=1,B为g,A为s,此时可通过dp[0][1](B为g,A为空),dp[1][0](B为空,A为s),dp[0][0](A为空,B为空)到,即dp[1][1]转化为dp[0][1],dp[1][0]或dp[0][0]三者后,在根据这三者求最小步骤。根据题目,dp[1][1]转化为dp[0][1],只需要删除A中的s。dp[1][1]转化为dp[1][0],只需要删除B中的
g,dp[1][1]转化为dp[0][0],只需要改变A或B的值。所以dp[1][1]=max(dp[1][0]+1,dp[0][1]+1,dp[1][1]+1);
其他同理,所以一般来讲,dp[i][j]=max(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+1);
但是如果A[i]=B[j],此时由于相同,我们不需要更改,所以自动忽略这两个字符,而去讨论这两个字符的前面的字符串,所以dp[i][j]=dp[i-1][j-1]
所以dp的表格是这样的
B\A | i=0 | i=1 | i=2 | i=3 | i=4 | i=5 | i=6 | i=7 |
j=0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
j=1 | 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
j=2 | 2 | 2 | 1 | 2 | 3 | 4 | 5 | 6 |
j=3 | 3 | 3 | 2 | 1 | 2 | 3 | 4 | 5 |
j=4 | 4 | 4 | 3 | 2 | 2 | 3 | 4 | 5 |
j=5 | 5 | 5 | 4 | 3 | 3 | 3 | 4 | 4 |
三,代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
#define inf 0x3f3f3f3f
int dp[2000][2000] = { 0 };
string str1, str2;
signed main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> str1 >> str2;
int N = max(str1.size(), str2.size());
for (int j = 1; j <= N; ++j) dp[j][0] = dp[0][j] = j;
for (int j = 1; j <= str2.size(); ++j)
{
for (int i = 1; i <= str1.size(); ++i)
{
dp[j][i] = inf;
if (str1[i - 1] == str2[j - 1]) dp[j][i] = dp[j - 1][i - 1];
else dp[j][i] = min(min(dp[j - 1][i], dp[j][i - 1]), dp[j - 1][i - 1]) + 1;
}
}
cout << dp[str2.size()][str1.size()];
return 0;
}