题目
有两个字符串(仅有英文小写字母组成) A,B。我们可以通过一些操作将 A 修改成 B。操作有三种:1 修改一个字母,2 删除一个字母,3 插入一个字母。现在定义编辑距离为将 A 通过上述操作修改成 B 的最少次数。
输入格式
第一行有一个正整数 N,表示有多少组测试数据
接下来有 2*N 行,每两行代表一组数据。每组数据的第一行是一个起始字符串 A,第二行是目的字符串 B。
输出格式
对于每组数据,输出一个值,表示将 A 修改成 B 的编辑距离、每组数据占一行,不要有多余空格。
N<=100 , A,B 字符串的长度不超过 500
样例
input
2
hello
hi
apple
google
output
4
4
解题思路
创建edit
数组,来记录动态规划以前的结果并且勇于后续迭代。
edit(i, j) 用来表示字符串A[1…i] 到 B[1…j]的编辑距离
i = 0, j = 0
,edit[0][0] = 0
i = 0, j > 0
,edit[0][j] = edit[0][j - 1] + 1
i > 0, j = 0
,edit[i][0] = edit[i - 1][0] + 1
i > 0, j > 0
A[i] == B[j]
, 不用变,edit[i][j] = edit[i - 1][j - 1]
A[i] != B[j]
- 替换,
edit[i][j] = edit[i - 1][j - 1] + 1
- 增加,把A[1…i]变成B[1…j-1],
edit[i][j] = edit[i][j - 1] + 1
- 删除,
edit[i][j] = edit[i - 1][j] + 1
- 替换,
综上所述,最终的状态转移方程是三个操作中最小的再加一。
int main(int argc, const char * argv[])
{
int N;
cin >> N;
for (int _ = 0; _ < N; ++_)
{
string tmp_ori, tmp_tar;
cin >> tmp_ori >> tmp_tar;
string ori = " ", tar = " ";
ori += tmp_ori; tar += tmp_tar;
int len_ori = ori.length(), len_tar = tar.length();
// input
int edit[len_ori][len_tar];
edit[0][0] = 0;
for (int i = 1; i < len_ori; ++i)
edit[i][0] = i;
for (int j = 1; j < len_tar; ++j)
edit[0][j] = j;
for (int i = 1; i < len_ori; ++i)
for (int j = 1; j < len_tar; ++j)
{
if (ori[i] == tar[j])
edit[i][j] = edit[i - 1][j - 1];
else
{
vector<int> max;
max.emplace_back(edit[i-1][j]);
max.emplace_back(edit[i-1][j-1]);
max.emplace_back(edit[i][j-1]);
edit[i][j] = *min_element(max.begin(), max.end()) + 1;
}
}
cout << edit[len_ori-1][len_tar-1] << endl;
}
return 0;
}