一、问题描述
给定一个序列X =
给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。最长公共子序列就是公共子序列中长度最长的子序列。
接下来简单明了地举例。X = ,X的子序列就是X序列元素按顺序组成的一个子集,比如 ,等。给定另一个序列Y = ,则就是X、Y的一个子序列,而、则是X、Y的最长公共子序列。
二、最优子结构证明
假设序列X =
①若xm = yn,那么zk=xm=yn,且Zk-1就是Xm-1和Yn-1的一个最长公共子序列。
②若xm ≠ yn,且zk ≠ xm,那么Zk就是Xm-1和Yn的一个最长公共子序列。
③若xm ≠ yn,且zk ≠ yn,那么Zk就是Xm和Yn-1的一个最长公共子序列。
证明:
①由已知,假设zk ≠ xm,那么则可以把xm(yn)放在公共子序列zk的末尾,这样就形成了一个新的公共子序列,且这个公共子序列的长度 = 原来的序列Z长度 + 1,与假设矛盾,所以 zk=xm=yn。再假设Zk-1不是Xm-1和Yn-1的最长公共子序列,说明存在一个更长的子序列,这时再把xm(yn)附在这个更长子序列的后面,则得到一个X和Y的更长的公共子序列,它的长度 > 原来的Z序列长度,与Z是X和Y的最长公共子序列矛盾,所以①成立。
②由已知,假设Zk不是Xm-1和Yn的最长公共子序列,那么存在一个比Zk更长的序列是Xm-1和Yn的公共子序列,而这个更长的序列肯定也是Xm和Yn的公共子序列,这个序列长度 > 原来Z序列,与Z是X和Y的最长公共子序列矛盾,所以②成立。
③ 同②。
三、递归方程
用c[i][j]表示Xi和Yj的最长公共子序列的长度。
0 if i = 0 or j = 0
c[i][j] = c[i-1][j-1] + 1 if i,j>0 and xi= yj
max{c[i-1][j],c[i][j-1]} if i,j>0 and xi ≠ yj
四、 Python代码实现(包括输出最长公共子序列)
import copy
def DPLength(X, Y, c, b):
for i in range(1, m+1):
for j in range(1, n+1):
if X[i-1] == Y[j-1]:
c[i][j] = c[i-1][j-1] + 1
b[i][j] = 1 # 1表示该字符是在公共子序列当中的
elif c[i-1][j] >= c[i][j-1]:
c[i][j] = c[i-1][j]
b[i][j] = 0 # 0表示不在公共子序列中
else:
c[i][j] = c[i][j-1]
b[i][j] = 2 # 2表示不在公共子序列但与0不同
return b and c
def PrintLCS(b, X, i, j): #打印重复部分
if i == 0 or j == 0:
return 0
if b[i][j] == 1:
PrintLCS(b, X, i-1, j-1)
print(X[i-1]) #注意二维列表中的i、j与X、Y序列(列表)差1
elif b[i][j] == 0:
PrintLCS(b, X, i-1, j)
else:
PrintLCS(b, X, i, j-1)
if __name__ == '__main__':
X = list(input())
Y = list(input())
print(X)
print(Y)
m = len(X)
n = len(Y)
c = [[] for i in range(m+1)]
for i in range(m+1):
for j in range(n+1):
c[i].append(0)
b = copy.deepcopy(c)
DPLength(X, Y, c, b)
PrintLCS(b, X, m, n)
print(c)
print("X在Y中的重复率达到:", c[m][n]/n*100, "%")
print("Y在X中的重复率达到:", c[m][n]/m*100, "%")
五、实验结果
输入:
X:ABCBDAB
Y: BDCABA
输出:
ABCBDAB
BDCABA
['A', 'B', 'C', 'B', 'D', 'A', 'B']
['B', 'D', 'C', 'A', 'B', 'A']
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
B
C
B
A
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1], [0, 1, 1, 1, 1, 2, 2], [0, 1, 1, 2, 2, 2, 2], [0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 2, 2, 3, 3], [0, 1, 2, 2, 3, 3, 4], [0, 1, 2, 2, 3, 4, 4]]
[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 2, 1], [0, 1, 2, 2, 0, 1, 2], [0, 0, 0, 1, 2, 0, 0], [0, 1, 0, 0, 0, 1, 2], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 1], [0, 1, 0, 0, 0, 1, 0]]
X在Y中的重复率达到: 66.66666666666666 %
Y在X中的重复率达到: 57.14285714285714 %
Process finished with exit code 0