给定两个字符串S和T,对于T我们允许三种操作:
(1) 在任意位置添加任意字符
(2) 删除存在的任意字符
(3) 修改任意字符
问最少操作多少次可以把字符串T变成S?
让串S和T的最长公共序列对齐,然后空出来的部分用'-'填充。
比如:S="ABCD",T="DBDE",对齐之后有
ABCD-
DB-DE
(2) S,T对应位置都是普通字符,不同,则需进行操作3。
(3) S在该位置是特殊字符,T在该位置是普通字符,则进行操作2。
(4) S在该位置是普通字符,T在该位置是特殊字符,则进行操作1。
参照求LCS时的状态,可以设dp[i][j]表示将S[i]和T[j]对齐后,需要的最少操作。
则dp[i][j]=min(dp[i-1][j-1]+(S[i]!=T[j]),dp[i-1][j]+1,dp[i][j-1]+1)
#include<bits/stdc++.h>
using namespace std;
typedef __int64 LL;
char S[1005],T[1005];
int dp[1001][1001];
int main()
{
int i,j;
cin>>S>>T;
int l1=strlen(S),l2=strlen(T);
for(i=0;i<=l1;++i) dp[i][0]=i;
for(i=0;i<=l2;++i) dp[0][i]=i;
for(i=1;i<=l1;++i)
for(j=1;j<=l2;++j)
dp[i][j]=min(dp[i-1][j-1]+(S[i-1]!=T[j-1]),min(dp[i-1][j],dp[i][j-1])+1);
printf("%d\n",dp[l1][l2]);
return 0;
}
空间复杂度优化:
#include<bits/stdc++.h>
using namespace std;
typedef __int64 LL;
char S[1005],T[1005];
int dp[2][1001];
int main()
{
int i,j;
cin>>S>>T;
int l1=strlen(S),l2=strlen(T);
for(i=0;i<=l2;++i) dp[0][i]=i;
for(i=1;i<=l1;++i){
dp[i&1][0]=i;
for(j=1;j<=l2;++j)
dp[i&1][j]=min(dp[!(i&1)][j-1]+(S[i-1]!=T[j-1]),min(dp[!(i&1)][j],dp[i&1][j-1])+1);
}
printf("%d\n",dp[!(i&1)][l2]);
return 0;
}