您的位置:首页 > 其它

OJ 72 Edit Distance

2017-08-27 17:52 211 查看
Description:

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character

b) Delete a character

c) Replace a character

描述:

给定两个字符串 s1,s2,找到从s1 转化成 s2所需要的最小变化次数,每一次变化计为1次

只允许使用下面三种操作:

1)插入一个字符

2)删除一个字符

3)替代一个字符

编辑距离问题是动态规划里面的问题之一,在算法导论书上的课后习题里面有这个题目的出现,算法导论的课后习题解答里面提供了递归的解题方法,但是时间复杂度太大,我们需要使用动态规划的备份思想来解决这个题目。

我们使用i 和 j 分别表示s1, s2 字符串的下标,那么:

1) 插入一个字符:需要把 i 和 j 都加1

2) 删除一个字符:需要把 i 加 1,j不变

3) 替代一个字符:需要把 i 和 j 都加 1

我们这里需要一个二维数组,来保存字符串转化的相关操作需要的操作数:

比如说我们需要把 ABCDEFG 转化成为 ACRG

那么我们的二维数组的初始状态为:



二维数组内的元素代表 s1 和 s2 子串互换所需要的操作数【互换表示s1 <->s2所需要的操作数一样】,比如s1的子串 “”(空字符串)要转化成为”A” “AC” “ACR” “ACRG” 所需要的最小次数分别为 1,2,3,4,那么我们就在相应的位置填上相应的数。

因我我们需要寻找的是最小的次数,那么我们需要跟上一个状态进行比较:上一个状态有下面三种情况:

1) s1子串不变,s2增加一个字符变化到s1

2) s2子串不变,s1增加一个字符变化到s2

3) s1, s2都增加一个字符,相互变化

这三种情况需要的次数分别对应二位数组里面的(i,j-1),(i-1,j),(i-1,j-1)【i为横坐标,j为纵坐标】

这两种情况其实是子问题的解,我们可以得到的递归关系式为:

d[i, j] = Min(d[i-1, j] + 1, d[i, j-1] + 1,d[i-1, j-1])

当两个子串的某一个字符相同时,我们直接把d[i-1, j-1]的值填入数组即可,因为不需要任何操作。

则我们按照行优先的顺序来处理这个数组,可以得到最后的数组为:



我们按照上面的思路就可以得到下面的代码:

int minDistance(string word1, string word2) {
int size1 = word1.size();
int size2 = word2.size();
vector<vector<int>> table(size1+1, vector<int>(size2+1, 0));
for (int i = 0; i < size2 + 1; ++i) {   //初始化第一行
table[0][i] = i;
}
for (int i = 0; i < size1 + 1; ++i) {   //初始化第一列
table[i][0] = i;
}

for (int i = 1; i < size1 + 1; ++i) {
for (int j = 1; j < size2 + 1; ++j) {
if (word1[j] == word2[i]) {
table[i][j] = table[i-1][j-1];
} else {
int min = min(table[i-1][j]+1, table[i][j-1]+1);
min = min(min, table[i-1][j-1]+1);
table[i][j] = min;
}
}
}

return table[size1][size2];
}

inline int min(int a, int b) {
return a > b ? b : a;
}


这个解法的空间复杂度和时间复杂度都是O(N^2)。如果使用暴力求解的话,时间复杂度将会是指数阶 [用空间来换时间]。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: