【问题描述】
设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括 (1)删除一个字符; (2)插入一个字符; (3)将一个字符改为另一个字符。 将字符串A变换为字符串B所用的最少字符操作数称为字符串A到 B的编辑距离,记为d(A,B)。 对于给定的字符串A和字符串B,计算其编辑距离 d(A,B)。
【算法描述】
A.问题分析三步曲
1). 子问题含义 d[i][j];//d[i][j]表示A[0:i]和B[0:j]的编辑距离
2).子问题的递归公式:
d[i][j]={0 i==0&&j==0
d[i][0]=i i>0&&j==0
d[0][j]=j i==0&&j>0
min(m[i-1][j]+1,m[i][j-1]+1,m[i-1][j-1]+num) i>0&&j>0
(num=A[i-1]=B[j-1]?0:1)
3).原问题的最优解是 d[m][n]
B.递归公式详解
1)若A,B均为空,则不需要做任何修改,d[i][j]=0
2)若A不为空,B为空,则需要删除A的所有内容得到B,d[i][j]=i
3) 若A为空,B不为空,则需要向A增加B的所有内容得到B,d[0][j]=j
4)若A,B两个串均不为空,则
当A[i-1]==B[j]时,需要删除A[i],d[i][j]= m[i-1][j]+1;
当A[i]==B[j-1]时,需要将B[j]加到A中,d[i][j]= m[i][j-1]+1;
当A[i-1]=B[j-1]时,d[i][j]= m[i-1][j-1]+0;否则,需要改写A[i-1],所以d[i][j]= m[i-1][j-1]+1。
所以此时d[i][j]= min(m[i-1][j]+1,m[i][j-1]+1,m[i-1][j-1]+num)
C. 使用方法:动态规划
- 二维数组(从递归公式左边可推断)
- 填表顺序(自上而下,自左向右)(因为原问题的最优解d[m][n]在右下角)
D. example A:fxpimu B:fwrs
表7*5
|
|
|
f |
w |
r |
s |
|
|
0 |
1 |
2 |
3 |
4 |
|
f |
1 |
0 |
1 |
2 |
3 |
|
x |
2 |
1 |
1 |
2 |
3 |
|
p |
3 |
2 |
2 |
2 |
3 |
|
i |
4 |
3 |
3 |
3 |
3 |
|
m |
5 |
4 |
4 |
4 |
4 |
|
u |
6 |
5 |
5 |
5 |
5 |
【算法时间及空间复杂度分析】
时间复杂度:该算法是对一个(m+1)(n+1)的表格进行填写的过程,填写每一个格d[i][j]花费的开销,只是根据 d[i-1][j], d[i][j-1], d[i-1][j-1], c[i-2][j-1]进行简单的加减运算,得到五个数字,选择其中最小的一个。所以该算法的时间复杂度为O(mn)。
空间复杂度: 该算法是对一个(m+1)(n+1)的表格进行填写的过程, 所以该算法的空间复杂度为O(mn)。
【程序运行截图】

【程序代码】
#include <iostream>
#include <string>
using namespace std;
int main()
{
string A,B;//定义字符串A,B
cin>>A;
cin>>B;
int m=A.length();//m为字符串A的长度
int n=B.length();//n为字符串B的长度
int a,b,c;
static int d[2000][2000];//填表 ,d[i][j]表示A[0:i]和B[0:j]的编辑距离
for(int i=0;i<=m;i++) d[i][0]=i;//填第一列
for(int j=0;j<=n;j++) d[0][j]=j;//填第一行
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
int num=(A[i-1]==B[j-1]? 0:1);
a=d[i-1][j]+1;//d[i][j]上面的格
b=d[i][j-1]+1;//d[i][j]左边的格
c=d[i-1][j-1]+num;//d[i][j]左上的格
d[i][j]=min(a,min(b,c));//三个格的最小值为最少字符操作数
}
}
cout<<d[m][n]<<endl;
}