数据结构与算法:动态规划之LCS最长公共子序列

什么是最长公共子序列:

一个序列S任意删除若干个字符得到的新序列T,则T叫做S的子序列

两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序 列

这里通过具体的例子来进行分析:

给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300

那么求两个序列中最长的公共子序列算法
– 生物学家常利用该算法进行基因序列比对,以推测序列的结构、功能和演化过程。

-- 描述两段文字之间的“相似度”

– 辨别抄袭,对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列 外的部分提取出来,该方法判断修改的部分

面对这个问题,如果不使用特殊的策略,而使用暴力搜索那么时间复杂度一定会爆表。关键在于子序列不一定是连续的子序列,可以是不连续的。所以类似问题我们一般使用动态规划来解决问题。动态规划的方法,我们可以用二维坐标来模拟

使用二维数组C[m,n]
C[i,j]记录序列X 和Y 的最长公共子序列的长度

– 当i=0或j=0时,空序列是X 和Y 的最长公共子序列,故C[i,j]=0 ij

下面我用图标表示,两个字符串ABCBDAB与BDCABA这两个最长公共子序列,通过图表的方式以二维坐标模拟得到最后的结果,最长公共子序列是4,一共有3个,分别是:BCAB,BDAB,BCBA

我们用python代码实现:

def lcs(first,second):
        vv = [[0]*50]*50
        #对中文进行编码,构造函数中的 error 参数指定了当输入的字节串无法用给定的编码方式进行转换时,函数的响应方式,'ignore' (在解码结果中去掉无法解码的字节
        first = unicode(first ,"utf-8",errors="ignore")
        second = unicode(second ,"utf-8",errors="ignore")
        #第一句的字长度
        lenFirst = len(first.strip())
        #第二句的字长度
        lenSecond = len(second.strip())
        #range的范围是[1,len+1),左闭右开
        for i in range(1,lenFirst+1):
                for j in range(1,lenSecond+1):
                        #计算动态规划时候是从0开始的,所以i和j相应的-1,至于减不减1根据你for循环的起始值
                        if first[i-1] == second[j-1]:
                                vv[i][j] = vv[i-1][j-1] + 1
                        else:
                                vv[i][j] = max(vv[i][j-1],vv[i-1][j])

        return float(vv[lenFirst][lenSecond]*2),float(lenFirst+lenSecond)

主要的逻辑在于如何使用二维数组的方式来模拟实现,即代码里面的双层循环。

猜你喜欢

转载自blog.csdn.net/Jameslvt/article/details/81080161