最长公共子序列(LCS) 过程图解

article/2025/9/28 10:06:40

1.基本概念

      首先需要科普一下,最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。什么是子序列呢?即一个给定的序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果。什么是子串呢?给定串中任意个连续的字符组成的子序列称为该串的子串。给一个图再解释一下:

       如上图,给定的字符序列: {a,b,c,d,e,f,g,h},它的子序列示例: {a,c,e,f} 即元素b,d,g,h被去掉后,保持原有的元素序列所得到的结果就是子序列。同理,{a,h},{c,d,e}等都是它的子序列。
       它的字串示例:{c,d,e,f} 即连续元素c,d,e,f组成的串是给定序列的字串。同理,{a,b,c,d},{g,h}等都是它的字串。

        这个问题说明白后,最长公共子序列(以下都简称LCS)就很好理解了。
给定序列s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2},s1和s2的相同子序列,且该子序列的长度最长,即是LCS。
s1和s2的其中一个最长公共子序列是 {3,4,6,7,8}

2.动态规划

       求解LCS问题,不能使用暴力搜索方法。一个长度为n的序列拥有 2的n次方个子序列,它的时间复杂度是指数阶,太恐怖了。解决LCS问题,需要借助动态规划的思想。
       动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。

3.特征分析

       解决LCS问题,需要把原问题分解成若干个子问题,所以需要刻画LCS的特征。

       设A=“a0,a1,…,am”,B=“b0,b1,…,bn”,且Z=“z0,z1,…,zk”为它们的最长公共子序列。不难证明有以下性质:
       如果am=bn,则zk=am=bn,且“z0,z1,…,z(k-1)”是“a0,a1,…,a(m-1)”和“b0,b1,…,b(n-1)”的一个最长公共子序列;
       如果am!=bn,则若zk!=am,蕴涵“z0,z1,…,zk”是“a0,a1,…,a(m-1)”和“b0,b1,…,bn”的一个最长公共子序列;
       如果am!=bn,则若zk!=bn,蕴涵“z0,z1,…,zk”是“a0,a1,…,am”和“b0,b1,…,b(n-1)”的一个最长公共子序列。

       有些同学,一看性质就容易晕菜,所以我给出一个图来让这些同学理解一下:

       以我在第1小节举的例子(S1={1,3,4,5,6,7,7,8}和S2={3,5,7,4,8,6,7,8,2}),并结合上图来说:

       假如S1的最后一个元素 与 S2的最后一个元素相等,那么S1和S2的LCS就等于 {S1减去最后一个元素} 与 {S2减去最后一个元素} 的 LCS  再加上 S1和S2相等的最后一个元素。

       假如S1的最后一个元素 与 S2的最后一个元素不等(本例子就是属于这种情况),那么S1和S2的LCS就等于 : {S1减去最后一个元素} 与 S2 的LCS, {S2减去最后一个元素} 与 S1 的LCS 中的最大的那个序列。

4.递归公式

        第3节说了LCS的特征,我们可以发现,假设我需要求 a1 ... am 和 b1 .. b(n-1)的LCS 和 a1 ... a(m-1) 和 b1 .. bn的LCS,一定会递归地并且重复地把如a1... a(m-1) 与 b1 ... b(n-1) 的 LCS 计算几次。所以我们需要一个数据结构来记录中间结果,避免重复计算。

        假设我们用c[i,j]表示Xi 和 Yj 的LCS的长度(直接保存最长公共子序列的中间结果不现实,需要先借助LCS的长度)。其中X = {x1 ... xm},Y ={y1...yn},Xi = {x1 ... xi},Yj={y1... yj}。可得递归公式如下:

         

5.计算LCS的长度

       这里我不打算贴出相应的代码,只想把这个过程说明白。还是以s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2}为例。我们借用《算法导论》中的推导图:

         图中的空白格子需要填上相应的数字(这个数字就是c[i,j]的定义,记录的LCS的长度值)。填的规则依据递归公式,简单来说:如果横竖(i,j)对应的两个元素相等,该格子的值 = c[i-1,j-1] + 1。如果不等,取c[i-1,j] 和 c[i,j-1]的最大值。首先初始化该表:

         

          然后,一行一行地从上往下填:

         

          S1的元素3 与 S2的元素3 相等,所以 c[2,1] = c[1,0] + 1。继续填充:

          

            S1的元素3 与 S2的元素5 不等,c[2,2] =max(c[1,2],c[2,1]),图中c[1,2] 和 c[2,1] 背景色为浅黄色。

            继续填充:

            

            

             

               中间几行填写规则不变,直接跳到最后一行:

              

                至此,该表填完。根据性质,c[8,9] = S1 和 S2 的 LCS的长度,即为5。

6.构造LCS

       本文S1和S2的最LCS并不是只有1个,本文并不是着重讲输出两个序列的所有LCS,只是介绍如何通过上表,输出其中一个LCS。

       我们根据递归公式构建了上表,我们将从最后一个元素c[8][9]倒推出S1和S2的LCS。

       c[8][9] = 5,且S1[8] != S2[9],所以倒推回去,c[8][9]的值来源于c[8][8]的值(因为c[8][8] > c[7][9])。

       c[8][8] = 5,  且S1[8] = S2[8], 所以倒推回去,c[8][8]的值来源于 c[7][7]。

       以此类推,如果遇到S1[i] != S2[j] ,且c[i-1][j] = c[i][j-1] 这种存在分支的情况,这里请都选择一个方向(之后遇到这样的情况,也选择相同的方向)。

       第一种结果为:

       

          这就是倒推回去的路径,棕色方格为相等元素,即LCS = {3,4,6,7,8},这是其中一个结果。

          如果如果遇到S1[i] != S2[j] ,且c[i-1][j] = c[i][j-1] 这种存在分支的情况,选择另一个方向,会得到另一个结果。

          

           即LCS ={3,5,7,7,8}。

7.关于时空复杂度

        构建c[i][j]表时间需要Θ(mn),空间需要n^2,输出1个LCS的序列需要Θ(m+n)。

本文来自 Running07 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/hrn1216/article/details/51534607?utm_source=copy


http://chatgpt.dhexx.cn/article/ZTnUs18D.shtml

相关文章

最长子序列问题详解

提到最长子序列问题,想必大家都不陌生,今天我主要想分享一下我对子序列问题的一些理解: 先拿最长上升子序列问题来说吧: 很明显这是一个动态规化问题,仔细想想也不难得出其状态转移方程 首先介绍一下dp[]数组的含义…

如何查看pip版本

Windows系统如何查看pip版本 直接运行pip show pip

python之pip版本问题

我们在默认安装python软件之后,其自行安装的pip的版本可能比较落后。我们使用pip安装模块的时候经常提示安装失败,查看安装失败原因,部分是因为pip不是最新版本需要升级版本才能继续安装,因此写下一点小心得,让我们都能…

pip 查看可安装版本

pip 查看可安装版本 pip版本: pip -V pip 20.1.1 from /usr/lib/python2.7/site-packages/pip (python 2.7) 查看pip可安装版本 import pip._internal.utils.compatibility_tags print(pip._internal.utils.compatibility_tags.get_supported())

python如何查看pip版本并且升级pip

第一次写Python的学习经历 我之前也安装过Python,今天,终于重新安装了64位的windows的Python,于是在命令行输入:“pip list”出现以下的提示: 这个提示以前也出现过,但是看不懂,也不知道怎么处理,然后又胡…

python pip 查找指定安装包版本信息

一、windows操作系统 pip list | findstr 查找的包(支持模糊查询)例: pip list | findstr huawei结果: 二、linux操作系统 pip list | grep 查找的包(支持模糊查询)

更新pip版本

更新pip版本 从报错来看是因为pip版本为20.2.3,但当前可用版本是21.0.1 python -m ensurepippython -m pip install --upgrade pippip list设置镜像默认源 #临时使用 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package #设置默认源 pip inst…

拉取的docker镜像中更换python以及pip版本

场景: 需要tensorflow1.10 python3.6 的环境,但是拉取的tf1.10镜像中,默认python版本是3.5 ,此时我们需要安装python3.6版本,将python命令的软连接删除,并且指向新安装的3.6,且pip的连接也应该…

Python查看所有版本及pip

1、查看python默认版本: python --version (默认的版本我改为了python3,所以结果是3.7的) 2、查看另外安装的2.7的版本: python2.7 --version 3、查看python安装路径: 1)终端输入python2.7回…

python降低pip版本

场景: 使用Pycharm开发时,经常会遇到因为pip版本过高而导致下载第三方库失败的情况 解决方案: 经查资料,发现可以通过降低pip的版本来解决问题 如下: 第一种方法:使用Terminal命令行进行降级 python -m pip…

Linux查看pip版本号的命令,pip 经常使用命令及控制台怎么查看python 及pip 和已安装包版本号...

在使用python的时候,常常使用到pip这个工具,能够很方便的线上安装依赖库,固然pip还有不少参数均可以帮咱们去查询一些库信息,在安装python的时候,下载带有pip的安装包就能够直接安装pip啦,固然没有带pip的&…

查看pip版本 及升级pip命令报错解决办法

pip install pytest_ordering时警告,pip版本过低 WARNING: You are using pip version 21.1.3; however, version 21.2.4 is available. You should consider upgrading 1、查看pip: pip show pip 2、升级pip:python -m pip install --upg…

最新升级pip命令,查看pip版本命令,pycharm升级pip命令,推荐收藏关注不迷路

1. 查看pip版本命令:pip -V ,可以看看以下代码运行完过后,自己的pip版本有没有升级成功 python升级pip命令:打开命令行输入 python -m pip install -U pip 回车 pycharm升级pip命令 :打开命令行输入: py…

[Python]pip查找包的历史版本

pip查找包的历史版本 场景:在一些时候通过pip install xxx 安装第三方库的时候默认情况下安装最新版本,由于是最新版本有个稳定性就不得不考虑其中,所以部分场景会存在一些bug这就要求我们安装历史版本,对一些更新频率比较高的三…

已解决正确查看pip版本、查看pip帮助命令

已解决(pip查看版本报错)Usage:pip [options] no such option: —verson 文章目录 报错代码报错翻译报错原因解决方法千人全栈VIP答疑群联系博主帮忙解决报错 报错代码 粉丝群一个小伙伴想用pip查看版本报错,但是发生了报错&#…

解决OpenSSL SSL_read: Connection was reset, errno 10054

报错问题: fatal: unable to access ‘https://github.com/Sunyt1992/ref-comet.git/’: OpenSSL SSL_read: Connection was reset, errno 10054 OpenSSL SSL_read:连接已重置,错误号10054 字面意思:服务器的SSL证书灭有经过第三方机构的签署…

TCP 10054

2019独角兽企业重金招聘Python工程师标准>>> TcpSocket:Connection reset by peer 10054 10054 ConnectionReset 客户端网络情况不好的条件下,比如正在下载其他东西,而服务器又有心跳超时处理,客户端的心跳迟迟发不上去&#xff0…

gitHub报错10054、443解决办法

为了学习netty框架,将netty的源码fork到自己的github账号下,使用IDEA进行下载,报了errno 10054的错误,如下所示: 21:40:24.692: [..\..\javaworkspace] git -c credential.helper -c core.quotepathfalse -c log.show…

git 提交10054

环境:goland 远端:github 在当前路径下执行: git config --global core.longpaths true