Edit Distance 题解
题目描述
即寻找两个字符串之间的编辑距离。编辑距离定义:
编辑距离是针对二个字符串(例如英文字)的差异程度的量化量测,量测方式是看至少需要多少次的处理才能将一个字符串变成另一个字符串。
如:kitten
和sitting
的最小编辑距离是3。
- kitten → sitten(k→s)
- sitten → sittin(e→i)
- sittin → sitting(+g)
题解
经典动态规划问题。将长度为m
字符串S
变成长度为n
字符串T
,其状态转移方程为:
$$ f(i,j) = \begin{cases} \sum_{k=1}^i CostOfDel(T_k) & \text{if $j = 0$ } \\[2ex] \sum_{k=1}^j CostOfIns(S_k) & \text{if $i = 0$ } \\[2ex] min \begin{cases} f(i-1,j)+CostOfDel(T_i) \\[2ex] f(i,j-1)+CostOfIns(S_j) \\[2ex] f(i-1,j-1)+CostOfSub(S_j,T_i) & \text{if $S_j \neq T_i$ } \\[2ex] f(i-1,j-1) & \text{if $S_j = T_i$ } \\[2ex] \end{cases} & \text{ others } \\[2ex] \end{cases} $$
f(i,j)
代表字符串S
的长度为j
的前缀子串变成字符串T
的长度为i
的前缀子串的最小编辑代价。
答案即f(n,m)
。状态数mn
个,状态转移复杂度O(1)
,因此时间复杂度为O(mn)
,空间复杂度为O(min(m,n))
。
此题中所有Cost*
函数的返回值都是1
。则状态转移方程可简化为
$$ f(i,j) = \begin{cases} i & \text{if $j = 0$ } \\[2ex] j & \text{if $i = 0$ } \\[2ex] f(i-1,j-1) & \text{if $S_j = T_i$ } \\[2ex] min \begin{cases} f(i-1,j)+1 \\[2ex] f(i,j-1)+1 \\[2ex] f(i-1,j-1)+1 \\[2ex] \end{cases} & \text{if $S_j \neq T_i$ } \\[2ex] \end{cases} $$
代码
#include <algorithm>
class Solution {
typedef int len_type;
public:
int minDistance(const string& src, const string& dest) {
if (dest.size() > src.size()) {
return minDistance(dest, src);
}
if (!dest.size())
return src.size();
if (!src.size())
return dest.size();
len_type len_src = src.size(), len_dest = dest.size();
len_type* const pc = new len_type[len_dest];
char c = src[0];
pc[0] = (c != dest[0]);
for (len_type j = 1; j < len_dest; ++j)
pc[j] = std::min((c != dest[j]) + j, pc[j - 1] + 1);
for (len_type i = 1; i < len_src; ++i) {
char c = src[i];
len_type lastj = pc[0];
pc[0] = std::min((c != dest[0]) + i, lastj + 1);
for (len_type j = 1; j < len_dest; ++j) {
len_type samej = pc[j];
pc[j] = std::min((c != dest[j]) + lastj, std::min(pc[j - 1], samej) + 1);
lastj = samej;
}
}
len_type dist = pc[len_dest - 1U];
delete [] pc;
return dist;
}
};
总结
主要应用了动态规划的思想。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。