动态规划
比较两个字符串时,若字符串
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实现思路,我便放弃了 ?。