问题描述
设A和B是两个字符串,要用最少的字符操作将字符串A转换成字符串B。这里所说的字符操作包括
1)删除一个字符;
2)插入一个字符;
3)将一个字符改为另一个字符。
将字符串A变换为字符串B所用的最少字符操作数成为字符串A到B的编辑距离,记为d(A,B)。对任给的2个字符串A和B,计算出它们的编辑距离d(A,B)。
问题分析
这是一道DP问题,DP问题的核心是“全局最优解的部分解是部分子问题的最优解”。构造字符串A,B如下
A: abcdef
B: acdefgh
全局最优解B=“abcdef”的部分解B1=“abcde”,是部分子问题A1=“abcde”,B1="acdef"的最优解,抓住此关键点,可知应对单个字符进行考虑,进而求出整个字符串的最优解。对第一个字符,B中的’a‘与A中的’a‘相同,因此可以不操作;第二个字符,B中的’c‘与A中的’b‘不同,则此时有三种情况:
1)删除’c‘
2)插入’b‘
3)将’c‘改为’b‘
计算三种情况下两个字符串中位置相同且字符相同的字符数量,选择最大那种方法,然后进行下一个字符的计算。遇到多余的字符,则直接删去并将编辑距离增加即可。此例中的计算步骤即为“acdefgh”=>"abcdefgh"=>"abcdef"。
上述方法有误,通过比较位置相同且字符相同的字符数量并不能衡量其是否是最优路径。关键步骤在于,
#include<iostream>
#include<string>
using namespace std;
int getEqualsNum(string &a, string &b) {
int num = 0;
for (unsigned int i = 0; i < a.length()&&i<b.length(); i++) {
if (a[i] == b[i])num++;
}
return num;
}
int max(int a, int b, int c) {
if (a > b&&a > c)return 1;
if (b > a&&b > c)return 2;
return 3;
}
int main() {
string a, b;
a = "abcdef";
b = "acdefg";
int res = 0;
for (unsigned int i = 0; i < a.length()&& i < b.length(); i++) {
if (a[i] == b[i])continue;
else {
//获取三种操作后的字符串与A串相等字符的个数
int add, del, change;
string c;
c = b;
c.insert(i, a, i);
add = getEqualsNum(a, c);
c = b;
c.erase(i, 1);
del = getEqualsNum(a, c);
c = b;
c[i] = a[i];
change = getEqualsNum(a, c);
//选取最优字串,对B串进行处理
int temp;
temp = max(add, del, change);
if (temp == 1)b.insert(i, a, i,1);
else if (temp == 2)b.erase(i, 1);
else b[i] = a[i];
res++;
}
}
int len1 = a.length(), len2 = b.length();
res += (len1 - len2) >= 0 ? (len1 - len2): -(len1 - len2);
cout << "A:" << a << endl << "B:" << b << endl;
cout << "Eidt Distance:" << res << endl;
system("pause");
return 0;
}