算法23--最长公共子序列以及子串

问题1:给定两个字符串,求其最大公共子序列

例如asbcdfg和scdfgjkl, 则返回scdfg

使用动态规划求解,

假设s1=<x1,x2....xn>  s2=<y1,y2..ym>

令f[i][j]表示串s1以索引i结尾,串s2以索引j结尾的最长公共子序列的长度。

当i==0或者j==0时,此时s1[i]  s2[j]均为空,即有f[i][j]=0

i>=1,j>=1

当s1[i]==s2[j]时,有f[i][j] = f[i-1][j-1] + 1

当s1[i]!=s2[j]时,有f[i][j] = max(f[i-1][j], f[i][j-1])

由于字符串s索引从0开始,为了便于计算,描述如下:

f[i][j]表示s1已i结尾,s2已j结尾的最大公共子序列:

i, j=0  f[i][j]=0

当s1[i]==s2[j]时,有f[i+1][j+1] = f[i][j] + 1

当s1[i]!=s2[j]时,有f[i+1][j+1] = max(f[i][j-1], f[i-1][j])

def testl():
    s1 = 'sabc'
    s2 = 'abcs'
    s = lcs(s1, s2)
    print (s)
    
def lcs(s1, s2):
    dp = [[0 for i in range(len(s1)+1)] for i in range(len(s2)+1)]
    for i in range(0, len(s1)):
        for j in range(0, len(s2)):
            if s1[i]==s2[j]:
                dp[i+1][j+1] = dp[i][j] + 1
            else:
                dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j])
    print (mat(dp))
    i = len(s1)
    j = len(s2)
    r = []
    while i>0 and j>0:
        #print (i,j,s1[i-1],s2[j-1])
        if s1[i-1]==s2[j-1]:
            r.append(s1[i-1])
            i -= 1
            j -= 1
        elif dp[i-1][j]==dp[i][j]:
            i -= 1
        else:
            j -= 1
    r.reverse()
    return r

动态规划数组如下所示:  表示0sabc 与0abcs的匹配关系:

现在找出最大的匹配子序列,

首先最大子序列长度值为dp[len(s1)][len(s2)],此时

若s1[i-1]==s2[j-1],即说明该字符即为公共字符,由于f[i][j] = f[i-1][j-1] + 1  可以沿对角斜向上寻找第二个字符 i--  j--

若两者不相等,则找出dp[i][j]的来源,由于f[i+1][j+1] = max(f[i][j-1], f[i-1][j]),要么左边,要么上边,若dp[i-1][j]==dp[i][j]说明来自上面,

则i--,否则j--

最后倒序输出序列即可。

问题2:给定两个字符串,求其最大公共子串

例如asbcdfg和scdfgjkl, 则返回cdfg  即必须是连续子串

s1=<x1,x2,,xm>

s2=<y1,y2...yn>

令f[i][j]表示s1以i结尾,s2以j结尾的最大公共子串:

i==0  j==0  f[i][j]=0

当s1[i]==s2[j]时,有f[i+1][j+1]=f[i][j]+1

当s1[i]!=s2[i]时,有f[i][j]=0

def lcs2(s1, s2):
    dp = [[0 for i in range(len(s1)+1)] for i in range(len(s2)+1)]
    row = 0
    col = 0
    max = 0
    for i in range(0, len(s1)):
        for j in range(0, len(s2)):
            if s1[i]==s2[j]:
                dp[i+1][j+1] = dp[i][j] + 1
                if(dp[i][j] + 1>max):
                    max = dp[i][j] + 1
                    row = i
                    col = j
            else:
                dp[i+1][j+1] = 0
    print (mat(dp))       
    return s1[i-max+1:i+1]

利用一个变量max来记录最大子串长度,利用row记录最大公共子串的最后一个字符在s1中的位置,返回最大公共子串:s1[i-max+1:i+1]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值