题意:
如题。
思路:
f[i][j] 状态表示 :
-
集合:所有将
a[1 ~ i]
变成b[1 ~ j]
的 操作方式 -
属性:操作数的最小值
min
状态计算 :依据最后一步考虑
三种操作,对应 f[i][j]
代表集合共有 三个子集
- ① 删除操作:把
a[i]
删掉之后a[1 ~ i]
转化成了b[1 ~ j]
所以之前要先做到a[1 ~ (i-1)]
和b[1 ~ j]
匹配
f[i-1][j] + 1
- ② 插入操作:插入之后
a[1 ~ i]
转化成了b[1 ~ j]
,所以插入的就是b[j]
那填之前a[1 ~ i]
和b[1 ~ (j-1)]
匹配
f[i][j-1] + 1
- ③ 替换操作:把
a[i]
改成b[j]
之后想要a[1 ~ i]
转化成b[1 ~ j]
那么修改这一位之前,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
,即得答案。
细节:初始化
先考虑有 哪些需要初始化
- 1.观察在
for
遍历时,需要用到 但是 事先没有的状态,就要预处理 (往往是0、1之类) - 2.如果求
min
的话,初始化为正无穷inf
,如求有负数的max
则初始化为-inf
对应的:
f[0][i]
如果a
串 初始长度就是0
,那么只能用插入操作让它变成b
串
f[i][0]
同样地,如果b
串 的长度是0
,那么a
只能用删除操作让它变成b
串f[i][j] = inf
,虽说这里没有用到,但是把考虑到的边界都写上还是保险
时间复杂度:
O ( n 2 ) O(n^2) O(n2)
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int N = 1010;
int n, m;
int dp[N][N];
char a[N], b[N];
int main()
{
scanf("%d%s", &n, a+1);
scanf("%d%s", &m, b+1);
//初始化
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
dp[i][j] = inf;
for(int i=1; i<=n; ++i) dp[i][0] = i;
for(int i=1; i<=m; ++i) dp[0][i] = i;
//状态计算
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=m; ++j)
{
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1);
if(a[i]==b[j]) dp[i][j] = min(dp[i][j], dp[i-1][j-1]);
else dp[i][j] = min(dp[i][j], dp[i-1][j-1]+1);
}
}
printf("%d\n", dp[n][m]);
return 0;
}