动态规划
比较两个字符串时,若字符串xxx长度为m,字符串yyy长度为n。
假设这两个字符串之间的编辑距离为E(m,n)E(m,n)E(m,n)。
要通过动态规划的方式解决它,那就需要将这样一个问题划分为子问题E(i,j)E(i,j)E(i,j),子问题表示串xxx中前iii个字符与串yyy中前jjj个字符之间的编辑距离。
当计算子串的编辑距离时,子串的最右边一列对齐时有以下三种情形:
_x[i]x[i]y[j]_y[j]\ \_ \qquad \qquad x[i] \qquad \qquad x[i] \\ y[j] \qquad \qquad \_ \qquad \qquad y[j] _x[i]x[i]y[j]_y[j]
根据以上的对齐方式,可以得到E(i,j)E(i,j)E(i,j)的递推公式:
E(i,j)=min{1+E(i−1,j), 1+E(i,j−1), diff(i,j)+E(i−1,j−1)};If x[i]==y[i] then diff(i,j)=0, otherwise diff(i,j)=1;E(0,j)=j; E(i,0)=iE(i,j) = min\{ 1+E(i-1,j), \ 1+E(i,j-1), \ diff(i,j)+E(i-1,j-1) \} ; \\ If \ x[i]==y[i] \ then \ diff(i,j)=0,\ otherwise \ diff(i,j)=1; \\ E(0,j)=j; \ E(i,0)=iE(i,j)=min{1+E(i−1,j), 1+E(i,j−1), diff(i,j)+E(i−1,j−1)};If x[i]==y[i] then diff(i,j)=0, otherwise diff(i,j)=1;E(0,j)=j; E(i,0)=i
根据以上递推公式,便能计算并填写下列表格,最终的E(m,n)E(m,n)E(m,n)即为最小编辑距离
E(i,j)E(i,j)E(i,j) | x[1] | x[2] | … | x[i] | … | x[m] | |
---|---|---|---|---|---|---|---|
0 | 1 | 2 | … | i | … | m | |
y[1] | 1 | ||||||
y[2] | 2 | ||||||
… | … | ||||||
y[j] | j | ||||||
… | … | ||||||
y[n] | n |
计算编辑距离的时间复杂度为
O(m⋅n)O(m \cdot n)O(m⋅n)
计算出编辑距离后,要想求出字符串的编辑位置,则可以从E(m,n)E(m,n)E(m,n)开始与左边、上边或左上角移动一格的区域中找出最小的一个编辑距离即Edmin=min{E(m−1,n), E(m,n−1), E(m−1,n−1)}Ed_{min}=min\{ E(m-1,n), \ E(m,n-1), \ E(m-1,n-1) \}Edmin=min{E(m−1,n), E(m,n−1), E(m−1,n−1)},将其与E(m,n)E(m,n)E(m,n)比较,若两者相等则说明x[m]x[m]x[m]与y[n]y[n]y[n]是对齐且相等的;否则认为这一位置是编辑点。同时继续以EdminEd_{min}Edmin对应的位置开始继续以上的步骤。
?
如下图说示,为两字符串的编辑位置。
给定一个加权完全图G=(V,E)G=(V,E)G=(V,E),每条边都有对应一个权值。试寻找一个简单的环路(不闭合),这个环路经过每个顶点恰好一次,并且总权值最小。
如下所示的图,图中有n=5n=5n=5个顶点,假设起点是A点,则从起点开始逐一访问其余顶点形成的所有可能路径是其余4个点的排列P(n−1n−1)P(^{n-1}_{n-1})P(n−1n−1),使用动态规划的话,能
动态规划的解法思路是:
对于一个子集S⊆{1,2,...,n}S\subseteq \{ 1,2,...,n\}S⊆{1,2,...,n}且1∈S,j∈S.1 \in S , j \in S.1∈S,j∈S.
让C(S,j)C(S, j)C(S,j)表示从起点111开始经过了集合SSS中所有顶点一次且终止于jjj的路径的最短长度。将C(S,j)C(S, j)C(S,j)表示为更小的子问题:
C(S,j)=minC(S−{j},i)+dijC({1},1)=0C(S, j) = min C(S- \{ j \}, i) + d_{ij} \\ C(\{ 1\} ,1)=0C(S,j)=minC(S−{j},i)+dijC({1},1)=0
有了以上的递推公式,便能进行相应的动态规划算法设计了,先从大小为2的集合S(∣S∣=2,且起点1∈S)S (|S|=2, 且起点1 \in S)S(∣S∣=2,且起点1∈S)开始,赋值C(S,1)=∞C(S, 1) = \inftyC(S,1)=∞,找出SSS中的元素j(j≠1,j非起点)j(j \neq1,j非起点)j(j̸=1,j非起点),对C(S,j)C(S,j)C(S,j)执行上述递推公式。之后逐渐扩大集合S的大小直至nnn,并重复上述步骤。
伪代码:
C({1},1)=0C(\{ 1\} ,1)=0C({1},1)=0
for h=2 to n do
for all subsets
S⊆{1,2,...,n}S \subseteq \{1,2,...,n \}S⊆{1,2,...,n}of size h and containing 1 do
C(S,1)=∞C(S,1) = \inftyC(S,1)=∞
for all
j∈S,j≠1j \in S, j \neq 1j∈S,j̸=1do
C(S,j)=minC(S−{j},i)+dijC(S, j) = min C(S- \{ j \}, i) + d_{ij}C(S,j)=minC(S−{j},i)+dij
return
minjC({1,2,...,n},j)+dj1min_j C( \{ 1,2,...,n \}, j) +d_{j1}minjC({1,2,...,n},j)+dj1
这种算法思路清晰,但是在实现算法的时候,需要设计合适ADT来表示图及顶点集合,我尝试过编写代码,但限于没有较好的ADT实现思路,我便放弃了 ?。