目录
最大公共子序列问题
子序列定义
一个序列去掉任意零个或多个元素剩余的序列。
问题的形式化定义
给定两个序列 X = ( x 1 , x 2 , . . . , x m ) X=(x_1, x_2,...,x_m) X=(x1,x2,...,xm), Y = ( y 1 , y 2 , . . . , y n ) Y=(y_1, y_2,...,y_n) Y=(y1,y2,...,yn),求一个最长的公共子序列 Z = ( z 1 , z 2 , . . . , z k ) Z=(z_1, z_2,...,z_k) Z=(z1,z2,...,zk),使对于所有的 p = 1 , 2 , . . . , k p=1,2,...,k p=1,2,...,k,有 z p = x i p = y j p z_p=x_{i_p}=y_{j_p} zp=xip=yjp。
第一步:定义最优解
定义 d i , j d_{i,j} di,j为序列 X [ 1 , … , i ] X[1,\dots,i] X[1,…,i]和 Y [ 1 , … , j ] Y[1,\dots,j] Y[1,…,j]的最长公共子序列长度。
第二步:建立递推关系
我们从两个序列的末尾开始向开头进行递推,这样在后续自底向上填表时就能从序列头进行填写。
如果两个序列的末尾元素是相同的,那么递推关系有三种情况:
d
i
,
j
=
m
a
x
{
d
i
−
1
,
j
−
1
+
1
d
i
−
1
,
j
d
i
,
j
−
1
(
X
[
i
]
=
Y
[
j
]
)
d_{i,j}=max\begin{cases}d_{i-1,j-1}+1\\d_{i-1,j}\\d_{i,j-1}\\\end{cases}( X[i]=Y[j])
di,j=max⎩
⎨
⎧di−1,j−1+1di−1,jdi,j−1(X[i]=Y[j])
事实上,
d
i
−
1
,
j
d_{i-1,j}
di−1,j或
d
i
,
j
−
1
d_{i,j-1}
di,j−1至多比
d
i
−
1
,
j
−
1
d_{i-1,j-1}
di−1,j−1大1。因此递推中第一种可能一定大于等于第二、第三种可能。可以仅保留第一项:
d
i
,
j
=
d
i
−
1
,
j
−
1
+
1
(
X
[
i
]
=
Y
[
j
]
)
d_{i,j}=d_{i-1,j-1}+1 (X[i]=Y[j])
di,j=di−1,j−1+1(X[i]=Y[j])
即相同的最后元素一定要被加入最长的公共子序列中。
如果两个序列的末尾元素是不同的,递推关系无非两种情况:
d
i
,
j
=
m
a
x
{
d
i
−
1
,
j
d
i
,
j
−
1
(
X
[
i
]
≠
Y
[
j
]
)
d_{i,j}=max \begin{cases}d_{i-1,j}\\d_{i,j-1}\\\end{cases} (X[i]\neq Y[j])
di,j=max{di−1,jdi,j−1(X[i]=Y[j])
综上所述,递推关系为:
d
i
,
j
=
{
d
i
−
1
,
j
−
1
+
1
(
X
[
i
]
=
Y
[
j
]
)
m
a
x
{
d
i
,
j
−
1
,
d
i
−
1
,
j
}
(
X
[
i
]
≠
Y
[
j
]
)
d_{i,j}=\begin{cases} d_{i-1,j-1}+1(X[i]= Y[j])\\ max\{d_{i,j-1}, d_{i-1,j}\}(X[i]\neq Y[j])\\ \end{cases}
di,j={di−1,j−1+1(X[i]=Y[j])max{di,j−1,di−1,j}(X[i]=Y[j])
第三步:自底向上计算(填表)与最优方案追踪
以
X
=
A
B
C
B
D
A
B
X=ABCBDAB
X=ABCBDAB,
Y
=
B
D
C
A
B
A
Y=BDCABA
Y=BDCABA为例。
为了追踪最优方案,应该记录每次递推时是从
d
i
−
1
,
j
−
1
d_{i-1,j-1}
di−1,j−1,
d
i
−
1
,
j
−
1
d_{i-1,j-1}
di−1,j−1还是
d
i
,
j
−
1
d_{i,j-1}
di,j−1得来,分别采取的操作是什么。建立追踪表,如果是从左上角推得(即元素相等),填写LU
;如果是从左边推得,填写L
;如果是从上面推得,填写U
。
Step 0
初始化表格:
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||
2 | 0 | ||||||
3 | 0 | ||||||
4 | 0 | ||||||
5 | 0 | ||||||
6 | 0 | ||||||
7 | 0 |
追踪表:
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | x | x | x | x | x | x | x |
1 | x | ||||||
2 | x | ||||||
3 | x | ||||||
4 | x | ||||||
5 | x | ||||||
6 | x | ||||||
7 | x |
Step 1
因为 X [ 1 ] ≠ Y [ 1 ] X[1]\neq Y[1] X[1]=Y[1], d 1 , 1 = m a x { d 0 , 1 , d 1 , 0 } = 0 d_{1,1}=max\{d_{0,1},d_{1,0}\}=0 d1,1=max{d0,1,d1,0}=0
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | |||||
2 | 0 | ||||||
3 | 0 | ||||||
4 | 0 | ||||||
5 | 0 | ||||||
6 | 0 | ||||||
7 | 0 |
追踪表:
当上面和左边的值相等时,不妨记为从上面推得。
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | x | x | x | x | x | x | x |
1 | x | U | |||||
2 | x | ||||||
3 | x | ||||||
4 | x | ||||||
5 | x | ||||||
6 | x | ||||||
7 | x |
…
Step N
因为 X [ 7 ] ≠ Y [ 6 ] X[7]\neq Y[6] X[7]=Y[6], d 7 , 6 = m a x { d 7 , 5 , d 6 , 6 } = 0 d_{7,6}=max\{d_{7,5},d_{6,6}\}=0 d7,6=max{d7,5,d6,6}=0
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
2 | 0 | 1 | 1 | 1 | 1 | 2 | 2 |
3 | 0 | 1 | 1 | 2 | 2 | 2 | 2 |
4 | 0 | 1 | 1 | 2 | 2 | 3 | 3 |
5 | 0 | 1 | 2 | 2 | 2 | 3 | 3 |
6 | 0 | 1 | 2 | 2 | 3 | 3 | 4 |
7 | 0 | 1 | 2 | 2 | 3 | 4 | 4 |
追踪表:
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | x | x | x | x | x | x | x |
1 | x | U | U | U | LU | L | LU |
2 | x | LU | L | L | U | LU | L |
3 | x | U | U | LU | L | U | U |
4 | x | LU | U | U | U | LU | L |
5 | x | U | LU | U | U | U | U |
6 | x | U | U | U | LU | U | LU |
7 | x | LU | U | U | U | LU | U |
从
d
7
,
6
d_{7,6}
d7,6倒推得到的序列为:LU
,L
,LU
,L
,LU
,U
,LU
,U
,其中LU
符号代表这个元素在公共子序列中。
个
X
X
X与
Y
Y
Y的4个公共子序列元素为:
X
[
2
]
X[2]
X[2],
X
[
3
]
X[3]
X[3],
X
[
4
]
X[4]
X[4],
X
[
6
]
X[6]
X[6]。即
B
C
B
A
BCBA
BCBA。
最长公共子串问题
子串定义
给定串中零个或多个连续的元素(如字符)组成的子序列。
问题的形式化定义
给定两个串 X = x 1 x 2 . . . x m X=x_1x_2...x_m X=x1x2...xm, Y = y 1 y 2 . . . y n Y=y_1y_2...y_n Y=y1y2...yn,求一个最长的公共子串 Z = z 1 z 2 . . . z k Z=z_1 z_2...z_k Z=z1z2...zk,使得存在下标 i i i和 j j j使得 x i x i + 1 . . . x i + k − 1 x_ix_{i+1}...x_{i+k-1} xixi+1...xi+k−1= y j y j + 1 . . . y j + k − 1 y_jy_{j+1}...y_{j+k-1} yjyj+1...yj+k−1。
第一步:定义最优解
定义 d i , j d_{i,j} di,j为串 X [ 1 , … , i ] X[1,\dots,i] X[1,…,i]的以 X [ i ] X[i] X[i]结尾的和 Y [ 1 , … , j ] Y[1,\dots,j] Y[1,…,j]的以 Y [ j ] Y[j] Y[j]结尾的最长的公共子串的长度。注意这样定义的 d m , n d_{m,n} dm,n一般不是我们需要的解的长度,我们最终要求的最优解的长度应该是 m a x { d i , j } max\{d_{i,j}\} max{di,j}。这里是为了便于建立递推关系,用到一种添加约束的小技巧,而不是直接去定义最优解的结构。
第二步:建立递推关系
如果两个串的末尾元素是相同的,那么递推关系就是:
d
i
,
j
=
d
i
−
1
,
j
−
1
+
1
(
X
[
i
]
=
Y
[
j
]
)
d_{i,j}=d_{i-1,j-1}+1(X[i]=Y[j])
di,j=di−1,j−1+1(X[i]=Y[j])
如果两个串的末尾元素不相同,递推终止:
d
i
,
j
=
0
(
X
[
i
]
≠
Y
[
j
]
)
d_{i,j}=0 (X[i]\neq Y[j])
di,j=0(X[i]=Y[j])
综上所述,递推关系为:
d
i
,
j
=
{
d
i
,
j
=
d
i
−
1
,
j
−
1
+
1
(
X
[
i
]
=
Y
[
j
]
)
d
i
,
j
=
0
(
X
[
i
]
≠
Y
[
j
]
)
d_{i,j}=\begin{cases} d_{i,j}=d_{i-1,j-1}+1(X[i]=Y[j])\\ d_{i,j}=0 (X[i]\neq Y[j])\\ \end{cases}
di,j={di,j=di−1,j−1+1(X[i]=Y[j])di,j=0(X[i]=Y[j])
第三步:自底向上计算(填表)与最优方案追踪
以
X
=
D
E
A
D
B
E
E
X=DEADBEE
X=DEADBEE,
Y
=
E
A
T
B
E
E
Y=EATBEE
Y=EATBEE为例。
本问题的递推关系比较简单,无需另外建立追踪表。只需要维护一个记录最长公共子串长度的全局变量
l
m
a
x
l_{max}
lmax和记录最长公共子串在
X
X
X串的结束位置的全局变量
p
m
a
x
p_{max}
pmax即可。
Step 0
初始化表格:
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||
2 | 0 | ||||||
3 | 0 | ||||||
4 | 0 | ||||||
5 | 0 | ||||||
6 | 0 | ||||||
7 | 0 |
l m a x = 0 l_{max}=0 lmax=0, p m a x = 0 p_{max}=0 pmax=0
Step 1
因为 X [ 1 ] ≠ Y [ 1 ] X[1]\neq Y[1] X[1]=Y[1], d 1 , 1 = 0 d_{1,1}=0 d1,1=0
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | |||||
2 | 0 | ||||||
3 | 0 | ||||||
4 | 0 | ||||||
5 | 0 | ||||||
6 | 0 | ||||||
7 | 0 |
l m a x = 0 l_{max}=0 lmax=0, p m a x = 0 p_{max}=0 pmax=0
…
Step N
因为 X [ 7 ] = Y [ 6 ] X[7]= Y[6] X[7]=Y[6], d 7 , 6 = d 6 , 5 + 1 = 3 d_{7,6}=d_{6,5}+1=3 d7,6=d6,5+1=3
0 | 1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
3 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
6 | 0 | 1 | 0 | 0 | 0 | 2 | 1 |
7 | 0 | 1 | 0 | 0 | 0 | 1 | 3 |
l m a x = 3 l_{max}=3 lmax=3, p m a x = 7 p_{max}=7 pmax=7
故最长公共子串的长度为3,其在 X X X串中的结束位置为7。得最长公共子串为 X [ 5 , 6 , 7 ] = B E E X[5,6,7]=BEE X[5,6,7]=BEE