我们定义 dp[i][j]
为将字符串 A[0..i-1]
转换为 B[0..j-1]
的最小操作数
状态转移
通过动态规划的思想,我们可以使用 状态转移方程 来计算 dp[i][j]
。具体来说,dp[i][j]
的值可以由以下几种操作得到:
-
如果
A[i-1] == B[j-1]
:- 如果
A[i-1]
和B[j-1]
相同,说明不需要对这两个字符做任何操作,那么我们只需从dp[i-1][j-1]
继承结果:
dp[i][j] = dp[i-1][j-1]
- 如果
-
如果
A[i-1] != B[j-1]
:- 删除操作 :从
A[0..i-1]
删除一个字符,使其变为A[0..i-2]
,即dp[i][j] = dp[i-1][j] + 1
。 - 插入操作 :从
B[0..j-1]
插入一个字符,变为B[0..j-2]
,即dp[i][j] = dp[i][j-1] + 1
。 - 替换操作 :将
A[i-1]
替换为B[j-1]
,即dp[i][j] = dp[i-1][j-1] + 1
。
- 删除操作 :从
-
选择最小操作数:
- 由于我们需要最少的操作数,因此
dp[i][j]
是以上三种操作中最小的操作数。
- 由于我们需要最少的操作数,因此
边界条件
在动态规划的过程中,我们需要先初始化边界条件:
-
dp[i][0]
:将A[0..i-1]
转换为空字符串,需要i
次删除操作:dp[i][0] = i
-
dp[0][j]
:将空字符串转换为B[0..j-1]
,需要j
次插入操作:dp[0][j] = j
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e4+4;
int dp[N][N];
int main() {
string a, b;
cin >> a >> b;
int m = a.size();
int n = b.size();
for (int i = 0; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (a[i - 1] == b[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}
else {
dp[i][j] = min({
dp[i - 1][j],dp[i][j - 1],dp[i - 1][j - 1]
}) + 1;
}
}
}
cout << dp[m][n] << endl;
return 0;
}