【算法】LCS最长公共子串DP

基础题型:

  1. 最长共公共子序列(不连续)lcs
  2. 最长公共子串(连续)lcstr
  3. 最长回文子序列(不连续)lps
  4. 最长回文子串(连续)lpstr

拓展题型

  1. 平方串(lcs拓展)
  2. 给定一个字符串,问是否能通过添加一个字母将其变为回文串(lcstr拓展)

 

 

1. 最长公共子序列LCS

输入:‘abcdef’,‘agbcje’

输出:‘abce’

Longest Common Subsequence Problem

#该版本是返回最长公共子串和其长度,若只返回长度,则可以简化
def LCS(s1,s2):
    m = len(s1)
    n = len(s2)
    res = [['' for i in range(n+1)] for j in range(m+1)]
    for i in range(1,m+1):
        for j in range(1,n+1):
            if s1[i-1] == s2[j-1]:
                res[i][j] = res[i-1][j-1] + s1[i-1]
            else:
                if len(res[i-1][j]) > len(res[i][j-1]):
                    res[i][j] = res[i-1][j]
                else:
                    res[i][j] = res[i][j-1]
    return res[-1][-1]

简化版本:只返回最长LCS的长度。

def lcs(s1, s2):
    l1 = len(s1)
    l2 = len(s2)
    # num[i][j]存储子串s1[0:i] 和 子串s2[0:j] 的lcs长度
    #由于考虑到空串也作为比较元素,则将两个字符串的长度各加一
    num = [[0 for i in range(l2+1)] for j in range(l1+1)]
    for i in range(1,l1+1):
        for j in range(1, l2+1):
            if s1[i-1] == s2[j-1]:
                num[i][j] = num[i-1][j-1]+1
            else:
                num[i][j] = max(num[i-1][j], num[i][j-1])
    return num[-1][-1]

2. 最长公共子串

输入:‘abcdef’,‘agbcje’

输出:‘bc’

def findLongest(A, n, B, m):
    val = 0
    res = [[0 for i in range(m + 1)] for j in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            if A[i - 1] == B[j - 1]:
                res[i][j] = res[i - 1][j - 1] + 1
            else:
                res[i][j] = 0
            val = max(val, res[i][j])
    return val

3. 最长回文子序列

输入:‘aucbcia’

输出:5

状态初始条件:dp[i][i]=1 (i=0:n-1)

状态转移方程:dp[l][r]=dp[l+1][r-1] + 2  if(str[l]==str[r])

                   dp[l][r]=max(dp[l+1][r],dp[l][r-1])  if (str[l]!=str[r])

def LPS(s):
    n = len(s)
    res = [[0 for i in range(n)] for j in range(n)]
    for i in range(n):
        res[i][i] = 1
    for r in range(n):
        for l in range(r-1, -1,-1):
            if s[l] == s[r]:
                res[l][r] = res[l+1][r-1] + 2
            else:
                res[l][r] = max(res[l+1][r], res[l][r-1])
    return res[0][n-1]

4. 最长回文子串

输入:‘aucbcia’

输出:5

初始条件:dp[i][i]=1,dp[i][i+1] = (S[i] == S[i+1]) ? 1 : 0。

def LPSeq(s):
    n = len(s)
    res = [[0 for i in range(n)] for j in range(n)]
    #初始条件
    for i in range(n):
        res[i][i] = 1
    for i in range(n-1):
        if s[i+1] == s[i]:
            res[i][i+1] = 1
    #以间隔为3开始查看
    for r in range(2,n):
        for l in range(r-3+1, -1, -1):
            if s[l] == s[r]:
                res[l][r] = res[l+1][r-1]
            else:
                res[l][r] = 0
    #计算最长长度
    val = 0
    for i in range(n):
        for j in range(i,n):
            if res[i][j] == 1:
                val = max(val,j-i+1)
    return val

1. 平方串

如果一个字符串S是由两个字符串T连接而成,即S = T + T, 我们就称S叫做平方串,例如"","aabaab","xxxx"都是平方串.
牛牛现在有一个字符串s,请你帮助牛牛从s中移除尽量少的字符,让剩下的字符串是一个平方串。换句话说,就是找出s的最长子序列并且这个子序列构成一个平方串。 

即将s分成两个子串,找出两个子串的lcs,然后取最大的lcs的二倍。

def squreStr(s):
    #将s分成两个子串,找出对应的lcs,在所有的lcs中找出最大的,其二倍即为对应的平方串的长度
    res = 0
    for i in range(1,len(s)):
        s1 = s[0:i]
        s2 = s[i:]
        res = max(res,lcs(s1,s2))
    return res*2

2. 给定一个字符串,问是否能通过添加一个字母将其变为回文串(lcstr拓展)

def justify(s):
    '''思路:判断原字符串和翻转字符串的最长公共子序列长度是否比原字符串长度小1或相等'''
    num = lcstr(s,s[::-1])
    if num == len(s) or num == (len(s)-1):
        return True
    else:
        return False
    
def lcstr(s1,s2):
    m = len(s1)
    n = len(s2)
    res = [[0 for i in range(n+1)] for j in range(m+1)]
    val = 0
    for i in range(m):
        for j in range(n):
            if s1[i] == s2[j]:
                res[i][j] = res[i-1][j-1]+1
            else:
                res[i][j] = 0
            val = max(val, res[i][j])
    return val

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值