给定两个字符串A和B,现在要将A经过若干操作变为B,可进行的操作有:
- 删除–将字符串A中的某个字符删除。
- 插入–在字符串A的某个位置插入某个字符。
- 替换–将字符串A中的某个字符替换为另一个字符。
现在请你求出,将A变为B至少需要进行多少次操作。
输入格式
第一行包含整数n,表示字符串A的长度。
第二行包含一个长度为n的字符串A。
第三行包含整数m,表示字符串B的长度。
第四行包含一个长度为m的字符串B。
字符串中均只包含大写字母。
输出格式
输出一个整数,表示最少操作次数。
数据范围
1 ≤ n,m ≤ 1000
输入样例:
10
AGTCTGACGC
11
AGTAAGTAGGC
输出样例:
4
题目大意:
给出两个字符串的长度和两个字符串AB,可以对串A进行三种操作:增、删、改,输出串A到串B至少需要几次操作。
解题思路:
线性dp问题,dp问题从两方面考虑
- 状态表示: 用两维去表示状态,f(i, j) 表示字符串 A 的前 i 个字符变化到字符串 B 的前 j 个字符所需的操作数, 本题要求的是最小值,所以f[i][j] 表示为A串的前 i 个字符变化到 B串的前 j 个字符所需的最小操作数。
- 状态计算: 考虑怎么转移到f[i][j],有增,删,改三种操作,考虑增加,即考虑f[i][j - 1] 串A的前 i 个字符变化到 B 的j - 1 个字符的最小操作数,A前 i 个字符已经和Bj - 1匹配,那么增加一个字符bj后才能做到ai bj 匹配。再考虑删除,先上状态:f[i - 1][j] + 1 删除之前,必须考虑a[i - 1] 已经和 b[j] 匹配上,才能实现删除一个字符匹配成功。而修改操作:考虑a[i - 1] 和 b[j - 1] 已经匹配,然后判断a[i] == b[j] 考虑是否 + 1。
Code:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e3 + 10;
int n, m;
char a[N], b[N];
int f[N][N];
int main()
{
scanf("%d%s%d%s", &n, a + 1, &m, 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;
f[i][j] = min(f[i][j], f[i - 1][j - 1] + (a[i] != b[j]));
}
cout << f[n][m] << endl;
return 0;
}