Python实现最长公共子序列(查重基础算法)

一、问题描述

    给定一个序列X = ,另一个序列Z = 是X的子序列,如果存在一个严格递增的X中元素下标的序列,使得Xij = Zj (1<=j<=k)。

     给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。最长公共子序列就是公共子序列中长度最长的子序列。

    接下来简单明了地举例。X =  ,X的子序列就是X序列元素按顺序组成的一个子集,比如 ,等。给定另一个序列Y = ,则就是X、Y的一个子序列,而则是X、Y的最长公共子序列。

二、最优子结构证明

    假设序列X = ,序列Y = ,序列Z = 为序列X和Y的某个最长公共子序列。那么:

①若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



你可能感兴趣的:(python,二维列表,查重算法,最长公共子序列)