• 动态规划之最长公共子序列


    动态规划之最长公共子序列

    1. 概念

    1. 公共子序列

    一个给定序列的子序列是在该序列中删去若干元素后得到的序列。如果序列Z既是序列X的子序列又是序列Y的子序列,则称Z是X和Y的公共子序列

    2. 最长公共子序列

    设序列,则 X m = x 1 , x 2 , … , x m , Y n = y 1 , y 2 , … , y n , Z k = z 1 , z 2 , … , z k X_m={x_1, x_2, …, x_m}, Y_n={y_1, y_2, …, y_n}, Z_k={z_1, z_2, …, z_k} Xm=x1,x2,,xm,Yn=y1,y2,,yn,Zk=z1,z2,,zk, 最长公共子序列分如下几种情况:

    • x m = y n x_m = y_n xm=yn, 则 Z k − 1 Z_{k-1} Zk1 X m − 1 X_{m-1} Xm1 Y n − 1 Y_{n-1} Yn1的最长公共子序列.
      如: X 3 = A , B , C ; Y 2 = B , C X_3=A,B,C; Y_2=B,C X3=A,B,C;Y2=B,C 则最长公共子序列 Z 2 = B , C Z_2=B,C Z2=B,C,则 Z 1 是 X 2 和 Y 2 最长公共子序列 Z_1是X_2和Y_2最长公共子序列 Z1X2Y2最长公共子序列
    • x m ≠ y n 且 x m ≠ z k x_m \neq y_n 且x_m \neq z_k xm=ynxm=zk, 则 Z Z Z X m − 1 X_{m-1} Xm1 Y Y Y的最长公共子序列.
      如: X 4 = A , B , C , H ; Y 3 = B , C , D X_4=A,B,C,H; Y_3=B, C, D X4=A,B,C,H;Y3=B,C,D 最长公共子序列 Z 2 = B , C Z_2=B,C Z2=B,C,其中 X 4 ≠ Y 3 且 X 4 ≠ Z 2 X_4 \neq Y_3且X_4 \neq Z_2 X4=Y3X4=Z2 Z 是 X 3 和 Y 3 Z是X_3和Y_3 ZX3Y3最长公共子序列
    • x m ≠ y n 且 y n ≠ z k x_m \neq y_n 且y_n \neq z_k xm=ynyn=zk, 则 Z Z Z X X X Y n − 1 Y_{n-1} Yn1的最长公共子序列.
      如: X 3 = B , C , D ; Y 4 = A , B , C , H ; X_3=B, C, D; Y_4=A,B,C,H; X3=B,C,D;Y4=A,B,C,H; 最长公共子序列 Z 2 = B , C Z_2=B,C Z2=B,C,其中 X 3 ≠ Y 4 且 Y 4 ≠ Z 2 X_3 \neq Y_4且Y_4 \neq Z_2 X3=Y4Y4=Z2 Z 是 X 3 和 Y 3 Z是X_3和Y_3 ZX3Y3最长公共子序列

    在分析上述最长公共子序列的情况中,当 x m = y n x_m = y_n xm=yn时,有一个子问题,即 :找出 x m − 1 = y n − 1 x_{m-1} = y_{n-1} xm1=yn1的最长公共子序列;当 x m ≠ y n x_m \neq y_n xm=yn时,有两个子问题:即找出 x m − 1 和 y x_{m-1} 和 y xm1y的最长公共子序列, 和 x 和 y n − 1 x 和 y_{n-1} xyn1的的最长公共子序列,这两个子问题都包含了同一个子问题 x m − 1 和 y n − 1 x_{m-1} 和y_{n-1} xm1yn1。 因此,本问题满足子问题重叠性质。
    进一步:
    c [ i ] [ j ] c[i][j] c[i][j]记录 X i 和 Y j X_i和Y_j XiYj的最长公共子序列的长度,则有:
    c [ i ] [ j ] = { 0 , i = 0 , j = 0 c [ i − 1 ] [ j − 1 ] + 1 , x i = x j max ⁡ { c [ i ] [ j − 1 ] , c [ i − 1 ] [ j ] } , x i ≠ x j c[i][j] = \begin{cases} 0, & \text i=0,j=0 \\ c[i-1][j-1] + 1, & \text x_i = x_j \\ \max\{c[i][j - 1], c[i - 1][j]\} , & \text x_i \neq x_j \end{cases} c[i][j]= 0,c[i1][j1]+1,max{c[i][j1],c[i1][j]},i=0j=0xi=xjxi=xj

    2. 程序跟踪

    2.1 过程跟踪

    例1:
    X 4 = A , C , B , D ; Y 4 = A , B , D , A X_4 = A,C, B,D; Y_4 = A, B, D, A X4=A,C,B,D;Y4=A,B,D,A
    过程:

    • i = 1 , j = 1 ; x 1 = y 1 ; 则 c [ 1 ] [ 1 ] = c [ 0 ] [ 0 ] + 1 = 1 i=1,j=1;x_1=y_1;则c[1][1]=c[0][0]+1 = 1 i=1,j=1;x1=y1;c[1][1]=c[0][0]+1=1
    • i = 1 , j = 2 ; x 1 ≠ y 2 ; 则 c [ 1 ] [ 2 ] = max ⁡ { c [ 1 ] [ 1 ] , c [ 0 ] [ 2 ] } = 1 i=1,j=2;x_1\neq y_2;则c[1][2]= \max\{c[1][1], c[0][2]\} = 1 i=1,j=2;x1=y2;c[1][2]=max{c[1][1],c[0][2]}=1
    • i = 1 , j = 3 ; x 1 ≠ y 3 ; 则 c [ 1 ] [ 3 ] = max ⁡ { c [ 1 ] [ 2 ] , c [ 0 ] [ 3 ] } = 1 i=1,j=3;x_1\neq y_3;则c[1][3]= \max\{c[1][2], c[0][3]\} = 1 i=1,j=3;x1=y3;c[1][3]=max{c[1][2],c[0][3]}=1
    • i = 1 , j = 4 ; x 1 = y 4 ; 则 c [ 1 ] [ 4 ] = c [ 0 ] [ 3 ] + 1 = 1 i=1,j=4;x_1= y_4;则c[1][4]=c[0][3]+1 = 1 i=1,j=4;x1=y4;c[1][4]=c[0][3]+1=1
    • i = 2 , j = 1 ; x 2 ≠ y 1 ; 则 c [ 2 ] [ 1 ] = max ⁡ { c [ 1 ] 1 ] , c [ 2 ] [ 0 ] } = 1 i=2,j=1;x_2\neq y_1;则c[2][1]= \max\{c[1]1], c[2][0]\} = 1 i=2,j=1;x2=y1;c[2][1]=max{c[1]1],c[2][0]}=1
      …依次类推

    b矩阵:
    0 表示没有移动。
    1 表示向上移动。
    2 表示向左移动。
    3 表示斜左上移动。

    LCS回溯
    从表格的右下角开始,检查当前位置对应的字符是否相等,若相等则左上移动;若不相等比较上面和左边两个单元格,选择较大的方向移动。继续上面过程直到c[0][0]

    c矩阵:

    00(A)0(B)0(D)0(A)
    0(A)1111
    0(C)1↑111
    0(B)12↖22
    0(D)123↖3←

    b矩阵:

    00000
    01221
    03222
    03122
    03312

    例2:
    X 4 = B , C , A , D ; Y 4 = C , A , B , D X_4 = B,C, A,D; Y_4 = C, A, B, D X4=B,C,A,D;Y4=C,A,B,D
    过程:

    • i = 1 , j = 1 ; x 1 ≠ y 1 ; 则 c [ 1 ] [ 1 ] = max ⁡ { c [ 1 ] [ 0 ] , c [ 0 ] [ 1 ]   = 0 i=1,j=1;x_1\neq y_1;则c[1][1]=\max\{c[1][0], c[0][1]\ = 0 i=1,j=1;x1=y1;c[1][1]=max{c[1][0],c[0][1] =0
    • i = 1 , j = 2 ; x 1 ≠ y 2 ; 则 c [ 1 ] [ 2 ] = max ⁡ { c [ 1 ] [ 1 ] , c [ 0 ] [ 2 ] } = 0 i=1,j=2;x_1\neq y_2;则c[1][2]= \max\{c[1][1], c[0][2]\} = 0 i=1,j=2;x1=y2;c[1][2]=max{c[1][1],c[0][2]}=0
    • i = 1 , j = 3 ; x 1 = y 3 ; 则 c [ 1 ] [ 3 ] = c [ 0 ] [ 2 ] + 1 = 1 i=1,j=3;x_1= y_3;则c[1][3]= c[0][2] + 1 = 1 i=1,j=3;x1=y3;c[1][3]=c[0][2]+1=1
    • i = 1 , j = 4 ; x 1 ≠ y 4 ; 则 c [ 1 ] [ 4 ] = max ⁡ { c [ 0 ] [ 3 ] , c [ 1 ] [ 3 ] } = 1 i=1,j=4;x_1\neq y_4;则c[1][4]= \max\{c[0][3], c[1][3]\} = 1 i=1,j=4;x1=y4;c[1][4]=max{c[0][3],c[1][3]}=1
    • i = 2 , j = 1 ; x 2 = y 1 ; 则 c [ 2 ] [ 1 ] = c [ 1 ] [ 0 ] + 1 = 1 i=2,j=1;x_2 = y_1;则c[2][1]=c[1][0] + 1 = 1 i=2,j=1;x2=y1;c[2][1]=c[1][0]+1=1
      …依次类推

    c矩阵:

    00000
    00011
    01111
    01222
    01223

    b矩阵:

    00000
    02213
    01322
    02133
    02221

    2.2 算法

    def lcs_subsequence(x, y):
        m = len(x)
        n = len(y)
    
        # 创建一个二维表格(m+1)*(n+1),初始值都为0;存储LCS长度即c[i][j]
        dp = [[0] * (n + 1) for _ in range(m + 1)]
    
        # 采用动态规划算法(相关的公式)填充表格
        for i in range(1, m+1):
            for j in range(1, n+1):
                if x[i-1] == y[j-1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                else:
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
                    
        # 输出LCS的长度
        lcs_length = dp[m][n]
        print("最长公共子序列 (LCS) 的长度:", lcs_length)
    
        # 回溯构建LCS
        lcs = []
        i, j = m, n
        while i > 0 and j > 0:
            if x[i - 1] == y[j - 1]:
                lcs.append(x[i - 1])
                i -= 1
                j -= 1
            elif dp[i - 1][j] > dp[i][j - 1]:
                i -= 1
            else:
                j -= 1
    
        lcs.reverse()
        return lcs
    
    if __name__ == "__main__":
        x = "ACBD"
        y = "ABDA"
        result = lcs_subsequence(x, y)
        print("最长公共子序列 (LCS):", "".join(result))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    运行结果:
    在这里插入图片描述

  • 相关阅读:
    260. 只出现一次的数字 III
    【力扣刷题】Day09——字符串专题
    基于springboot实现漫画网站管理系统项目【项目源码+论文说明】
    软考高项——47个过程的输入、输出、工具技术汇总
    Part2_扩展MATSIM_Subpart13_开发过程和自己的模块_第45章 如何编写自己的扩展并可能将其贡献给Matsim
    工匠的发展与兴衰趋势-机器人篇
    基于springboot的社区医院管理系统的设计
    【线性代数】三、特征值和特征向量
    【比特熊故事汇2.0】|即使每天都是新的探险,他也会快乐Say Hi
    WPF-控件的常用属性-单例-隧道事件
  • 原文地址:https://blog.csdn.net/fulishafulisha/article/details/133760388