题目链接
题目描述
设 A A A 和 B B B 是两个字符串。我们要用最少的字符操作次数,将字符串 A A A 转换为字符串 B B B。这里所说的字符操作共有三种:
- 删除一个字符;
- 插入一个字符;
- 将一个字符改为另一个字符。
A , B A, B A,B 均只包含小写字母。
输入格式
第一行为字符串 A A A;第二行为字符串 B B B;字符串 A , B A, B A,B 的长度均小于 2000 2000 2000。
输出格式
只有一个正整数,为最少字符操作次数。
样例 #1
样例输入 #1
sfdqxbw
gfdgw
样例输出 #1
4
提示
对于 100 % 100 \% 100% 的数据, 1 ≤ ∣ A ∣ , ∣ B ∣ ≤ 2000 1 \le |A|, |B| \le 2000 1≤∣A∣,∣B∣≤2000。
算法思想
-
状态表示
f[i][j]
表示将字符串 A A A中前i
个字符编辑成字符串 B B B中前j
个字符所要进行的最少操作次数。 -
状态计算,根据最后一步的情况,可以将操作分为 3 3 3类:
- 删除字符
A
i
A_i
Ai使得两个字符串相匹配,那么要先做到
A
[
1...
i
−
1
]
A[1...i-1]
A[1...i−1] 和
B
[
1...
j
]
B[1...j]
B[1...j]相同,因此操作次数为
f[i-1][j] + 1
- 插入字符
B
j
B_j
Bj使得两个字符串相匹配,那么要先做到
A
[
1...
i
]
A[1...i]
A[1...i] 和
B
[
1...
j
−
1
]
B[1...j-1]
B[1...j−1]相同,因此操作次数为
f[i][j-1] + 1
- 替换字符
A
i
A_i
Ai为
B
j
B_j
Bj使得字符串相匹配,又需要分两种情况讨论:
-
A
i
=
B
j
A_i=B_j
Ai=Bj,操作次数
f[i-1][j-1]
-
A
i
≠
B
j
A_i\ne B_j
Ai=Bj,操作次数
f[i-1][j-1] + 1
-
A
i
=
B
j
A_i=B_j
Ai=Bj,操作次数
最终,
f[i][j]
应取以上三种情况的最小值。 - 删除字符
A
i
A_i
Ai使得两个字符串相匹配,那么要先做到
A
[
1...
i
−
1
]
A[1...i-1]
A[1...i−1] 和
B
[
1...
j
]
B[1...j]
B[1...j]相同,因此操作次数为
-
初始状态:
f[0][i] = i
,字符串A中插入i个字符f[i][0] = i
,字符串A中删除i个字符
时间复杂度
状态数为
O
(
n
×
m
)
O(n\times m)
O(n×m),状态计算过程为O(1)
。
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010;
char a[N], b[N];
int f[N][N];
int main()
{
cin >> a + 1 >> b + 1;
int n = strlen(a + 1), m = strlen(b + 1);
//初始状态
for(int i = 1; i <= n; i ++) f[i][0] = i;
for(int i = 1; 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], f[i][j - 1]) + 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);//不相等时替换
}
cout << f[n][m];
return 0;
}