使用 python 实现动态规划之最长公共子串

这道题属于动态规划中十分经典的题目,在两个字符串中找到最长的公共子串,返回其最大长度或最大字符串。

一、解题思路

我们可以让两个字符串分别作为一个二维矩阵的行和列,然后比较二维矩阵中每个点对应的行列字符串中的字符是否相同,如果相同设置为1,否则设置为0。接着只需要查找值为1的最长对角线就可以解决。
对于以下两个字符串为例:

str1="asdfas"
str2="werasdfaswer"

在这里插入图片描述
可以发现,我们所找寻的公共子串就是图中的几条对角线,而长的公共子串就是对角线最长的那一个。

二、动态规划

动态规划的核心就是如何转移,如何利用上一步的结果,根据当前的条件判断,得出现在状态的结果:
在这里插入图片描述

record[i][j]=1可以演变为record[i][j]=1+record[i-1][j-1]

三、函数实现输出最长公共子串长度

def lcs_max_num(str1, str2):
    m = len(str1)
    n = len(str2)
    max_num = 0
    # 构造一个(m+1)*(n+1)的二维数组来存储LCS的长度
    lcs_len = [[0] * (n + 1) for i in range(m + 1)]

    # 动态规划求解LCS的长度
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i - 1] == str2[j - 1]:
                lcs_len[i][j] = lcs_len[i - 1][j - 1] + 1
            if max_num < lcs_len[i][j]:
                max_num = lcs_len[i][j]
    return max_num

if __name__ == "__main__":
    str1 = 'asdfas'
    str2 = 'werasdfaswer'
    print(lcs_max_num(str1, str2))

四、函数实现输出最长公共子串

def lcs_max_char(str1, str2):
    m = len(str1)
    n = len(str2)
    # 构造一个(m+1)*(n+1)的二维数组来存储LCS的长度
    lcs_len = [[0] * (n + 1) for i in range(m + 1)]

    # 动态规划求解LCS的长度
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i - 1] == str2[j - 1]:
                lcs_len[i][j] = lcs_len[i - 1][j - 1] + 1
            else:
                lcs_len[i][j] = max(lcs_len[i - 1][j], lcs_len[i][j - 1])

    # 根据LCS的长度求解LCS的文本
    lcs_text = ""
    i = m
    j = n
    while i > 0 and j > 0:
        if str1[i - 1] == str2[j - 1]:
            lcs_text = str1[i - 1] + lcs_text
            i -= 1
            j -= 1
        elif lcs_len[i - 1][j] > lcs_len[i][j - 1]:
            i -= 1
        else:
            j -= 1

    return lcs_text

if __name__ == "__main__":
    str1 = 'asdfas'
    str2 = 'werasdfaswer'
    print(lcs_max_char(str1, str2))
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值