题目描述:
给定两个字符串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
分析:
本题要求将A转化为B的最小操作次数,状态表示:f[i][j]表示将A[1~i]转化为B[1~j]的最少操作次数。考察f[i][j]的状态可以由哪些状态转移而来?无非是由某种状态进行一步插入、删除或者替换操作,可将之前的状态转化为f[i][j],我们要思考的是如何由规模更小的子问题通过一步操作得到现在的状态。如果最后一步操作是插入一个元素,在此之前我们知道将A[1~i]转化为B[1~j-1]的最小操作次数f[i][j-1],再插入B[j]即可使得A与B匹配,则f[i][j] = f[i][j-1] + 1;如果最后一步操作是删除A[i],在此之前A[1~i-1]与B[1~j]应该是匹配的,则f[i][j] = f[i-1][j] + 1,;如果最后一步操作是修改A[i],则A[i] == B[j]时,这步不用操作,即f[i][j] = f[i-1][j-1];A[i] != B[j]时,需要修改A[i],即f[i][j] = f[i-1][j-1] + 1。
在我们知道了f[i-1][j],f[i][j-1]以及f[i-1][j-1]后,我们可以尝试从这三种状态的每一种状态转化成f[i][j]来计算出最小操作次数,即A[i] == B[j]时,f[i][j] = f[i-1][j-1];A[i] != B[j]时,f[i][j] = min(f[i][j-1],f[i-1][j],f[i-1][j-1]) + 1。
最后考虑边界情况,f[0][j]表示从无到B[1~j]的最小操作次数,显然是j次插入操作;f[i][0]表示将A[1~i]清空,显然是i次删除操作。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1005;
char a[maxn],b[maxn];
int f[maxn][maxn];
int main(){
int n,m;
scanf("%d",&n);
scanf("%s",a + 1);
scanf("%d",&m);
scanf("%s",b + 1);
for(int i = 0;i <= n;i++) f[i][0] = i;
for(int i = 0;i <= m;i++) f[0][i] = i;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++){
if(a[i] == b[j]) f[i][j] = f[i - 1][j - 1];
else f[i][j] = min(min(f[i - 1][j],f[i][j - 1]),f[i - 1][j - 1]) + 1;
}
}
printf("%d\n",f[n][m]);
return 0;
}