题目描述
给定两个字符串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
题解:
将一个字符串通过删除、插入、替换变为另一个字符串的最短距离,可以用动态规划来做,用f(i, j)来表示长度为i的字符串变为长度为j的字符串最小的操作次数,那么如何来求f(i, j)呢?对每个字符我们有3种操作:
1.删除:假设删除a[i]后,a[1 ~ i] 与 b[1 ~ j] 匹配,那么说明a[1 ~ i – 1]已经与b[1 ~ j]相等了,那么多出来的a[i]直接删掉即可,状态转移方程为:f(i, j) = f(i – 1, j) + 1
2.插入: 假设插入一个a[i],使a[i] == b[j]后,a[1 ~ i] 与 b[1 ~ j] 匹配,那么说明a[1 ~ i]已经与b[i ~ j – 1]相等了,要使a[1 ~ i]与b[i ~ j]相等,只需再a[1 ~ i]的后面添加一个b[j]即可
状态转移方程为:f(i, j) = f(i, j – 1) + 1
3.替换:假设将a[i]替换成b[j],使得a[1 ~ i] 与 b[1 ~ j] 匹配,那么说明a[1 ~ i – 1]已经与b[i ~ j – 1]相等了,要使a[1 ~ i]与b[i ~ j]相等,只需将a[i]替换为b[j]即可。
如果a[i] = b[j],则无需替换,状态转移方程为:f(i, j) = f(i – 1, j – 1)
如果a[i] != b[j],则需要替换,状态转移方程为:f(i, j) = f(i – 1, j – 1) + 1
所以我们得出来总的状态转移方程式为就是上述方程式的最小值
代码如下:
#include<iostream>
using namespace std;
const int N = 1010;
char s1[N], s2[N];
int f[N][N];
int main()
{
int n, m;
cin >> n >> s1 + 1;
cin >> m >> s2 + 1;
for(int i = 0; i <= n; i++) //a[i ~ i]变为0,只能删除, 操作数为i
f[i][0] = i;
for(int i = 0; i <= m; i++)//a[0]变为b[1 ~ i],只能添加,操作数为i
f[0][i] = i;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
//f[i - 1][j] + 1 表示进行删除操作
//f[i][j - 1] + 1 表示进行添加操作
f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
//下面的表示进行替换操作
if(s1[i] == s2[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] << endl;
return 0;
}