比较两个字符串时,若字符串 x x x长度为m,字符串 y y y长度为n。
假设这两个字符串之间的编辑距离为 E ( m , n ) E(m,n) E(m,n)。
要通过动态规划的方式解决它,那就需要将这样一个问题划分为子问题 E ( i , j ) E(i,j) E(i,j),子问题表示串 x x x中前 i i i个字符与串 y y y中前 j j j个字符之间的编辑距离。
当计算子串的编辑距离时,子串的最右边一列对齐时有以下三种情形:
_ 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 ) = m i n { 1 + E ( i − 1 , j ) , 1 + E ( i , j − 1 ) , d i f f ( i , j ) + E ( i − 1 , j − 1 ) } ; I f x [ i ] = = y [ i ] t h e n d i f f ( i , j ) = 0 , o t h e r w i s e d i f f ( i , j ) = 1 ; E ( 0 , j ) = j ; E ( i , 0 ) = i 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)=i 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)=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)开始与左边、上边或左上角移动一格的区域中找出最小的一个编辑距离即 E d m i n = m i n { 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]是对齐且相等的;否则认为这一位置是编辑点。同时继续以 E d m i n Ed_{min} Edmin对应的位置开始继续以上的步骤。
如下图说示,为两字符串的编辑位置。
给定一个加权完全图 G = ( V , E ) G=(V,E) G=(V,E),每条边都有对应一个权值。试寻找一个简单的环路(不闭合),这个环路经过每个顶点恰好一次,并且总权值最小。
如下所示的图,图中有 n = 5 n=5 n=5个顶点,假设起点是A点,则从起点开始逐一访问其余顶点形成的所有可能路径是其余4个点的排列 P ( n − 1 n − 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)表示从起点 1 1 1开始经过了集合 S S S中所有顶点一次且终止于 j j j的路径的最短长度。将 C ( S , j ) C(S, j) C(S,j)表示为更小的子问题:
C ( S , j ) = m i n C ( S − { j } , i ) + d i j C ( { 1 } , 1 ) = 0 C(S, j) = min C(S- \{ j \}, i) + d_{ij} \\ C(\{ 1\} ,1)=0 C(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) = \infty C(S,1)=∞,找出 S S S中的元素 j ( j ≠ 1 , j 非 起 点 ) j(j \neq1,j非起点) j(j̸=1,j非起点),对 C ( S , j ) C(S,j) C(S,j)执行上述递推公式。之后逐渐扩大集合S的大小直至 n n n,并重复上述步骤。
伪代码:
C ( { 1 } , 1 ) = 0 C(\{ 1\} ,1)=0 C({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) = \infty C(S,1)=∞
for all
j ∈ S , j ≠ 1 j \in S, j \neq 1 j∈S,j̸=1do
C ( S , j ) = m i n C ( S − { j } , i ) + d i j C(S, j) = min C(S- \{ j \}, i) + d_{ij} C(S,j)=minC(S−{j},i)+dij
return
m i n j C ( { 1 , 2 , . . . , n } , j ) + d j 1 min_j C( \{ 1,2,...,n \}, j) +d_{j1} minjC({1,2,...,n},j)+dj1
这种算法思路清晰,但是在实现算法的时候,需要设计合适ADT来表示图及顶点集合,我尝试过编写代码,但限于没有较好的ADT实现思路,我便放弃了 。