最长公共子序列

#问题描述 序列可以理解成一个字符串,比如“Chinese”就是一个序列,而子序列指的是由序列中的若干字符,按原相对次序构成的序列。需要注意的是,子序列中的各个字符的相对次序一定和原来序列中的相对次序一样。比如,“Cin”是“Chinese”的子序列,而“sin”就不是“Chinese”的子序列。最长公共子序列(Longest Common Subsequence)问题,就是要找出两个序列的最长的公共子序列。假设有一个长度为n的序列A[1,n]和一个长度为m的序列B[1,m],A和B的最长公共子序列可以记为LCS(A, B)。

#思路 对于序列A[0,n]和B[0,m],LCS(A, B)无非三种情况: 1.若n=0或m=0,则取作空序列(""); 2.若A[n] = 'X' = B[m],则取作LCS(A[1,n-1], B[1,m-1]) + 'X'; 3.若A[n] $\neq$B[m],则取在LCS(A[1,n], B[1,m-1])和LCS(A[1,n-1], B[1,m])中取更长者。 #代码 ##递归 根据以上思路,可以很容易用递归的方式写出代码,以下是用Python实现的代码:

def getLCS(str1, str2):
    str1_len = len(str1)
    str2_len = len(str2)
    if(str1_len == 0 or str2_len == 0):
        return ''
    if str1[str1_len-1] == str2[str2_len-1]:
        return getLCS(str1[:str1_len-1], str2[:str2_len-1]) + str1[str1_len-1]
    else:
        res1 = getLCS(str1[:str1_len-1], str2)
        res2 = getLCS(str1, str2[:str2_len-1])
        return res1 if len(res1) > len(res2) else res2

str1 = 'didactiC'
str2 = 'advant'

print(getLCS(str1, str2))

##迭代 上面所讲的递归算法虽然可以得到正确的结果,但是计算量大的惊人,时间复杂度几乎是$O(2^n)$,这是什么概念,就是如果两个序列的长度均为50,那么计算机要执行1125899906842624个递归实例,现代个人计算机每秒大概能计算10亿次,即使每个递归实例的执行时间仅为一个指令周期,那么执行完这个程序也要花费13天,这显然是我们不能接受的。所以要对算法进行改进。 改进的方法其实很简单,就是使用动态规划的方法,将递归改成迭代就可以了。 下面是修改后的代码:

def getLCS(str1, str2):
    str1_len = len(str1)
    str2_len = len(str2)
    c = [[0 for i in range(str2_len+1)] for i in range(str1_len+1)]#  创建一个二维数组,记录最长公共子序列的长度
    lcs = ''
    for i in range(1, str1_len + 1):
        haveSame = False #记录当前行有没有相同的字符,如果有,则将该变量置为True
        sameChar = '' #记录当前行相同的字符
        for j in range(1, str2_len + 1):
            if str1[i-1] == str2[j-1]:
                c[i][j] = c[i-1][j-1] + 1
                haveSame = True
                sameChar = str1[i-1]
            else:
                c[i][j] = c[i][j-1] if c[i][j-1] > c[i-1][j] else c[i-1][j]
        if haveSame and c[i][j] == len(lcs) + 1:
            lcs += sameChar
    return lcs

str1 = 'didactiC'
str2 = 'advant'
print(getLCS(str1, str2))

由于oschina不支持LaTeX数学公式,所以文中有些地方显示比较奇怪。想查看原文的朋友,请点击:最长公共子序列

欢迎关注我的V信公众号AProgrammer,更多干货等你来发现!

转载于:https://my.oschina.net/youngyoung123/blog/2878752

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值