python实现最大公共子序列

介绍

子序列和子串的意思不一样,如下图所示,子序列不要求连续,只需要在给定序列中出现过,并且相对顺序一致。而子串需要连续。
给定两个两个字符串
图片来自动态规划 最长公共子序列 过程图解

最长公共子序列(LCS):

同时出现在两个字符串中的最长子序列

实现

1143. 最长公共子序列

思想和求解两个字符串之间的编辑距离差不多,使用动态规划的方法,递推公式如下:

d p [ i , j ] dp[i, j] dp[i,j]表示字符串 x [ : i ] x[:i] x[:i]与字符串 y [ : j ] y[:j] y[:j]之间的最长公共子序列长度

d p [ i , j ] = { 0  若  i = 0  或  j = 0 d p [ i − 1 , j − 1 ] + 1  若  i , j ≥ 0 , x i − 1 = y j − 1 max ⁡ { d p [ i , j − 1 ] , d p [ i − 1 , j ] }  若  i , j ≥ 0 , x i − 1 ≠ y j − 1 dp[i, j]= \begin{cases}0 & \text { 若 } i=0 \text { 或 } j=0 \\ dp[i-1, j-1]+1 & \text { 若 } i, j\geq0, x_{i-1}=y_{j-1} \\ \max \{dp[i, j-1], dp[i-1, j]\} & \text { 若 } i, j\geq0, x_{i-1} \neq y_{j-1}\end{cases} dp[i,j]=0dp[i1,j1]+1max{dp[i,j1],dp[i1,j]}  i=0  j=0  i,j0,xi1=yj1  i,j0,xi1=yj1

代码如下:

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        m = len(text1)
        n = len(text2)

        res = ""
        # 记录最长的公共子序列

        if m * n == 0:
            return 0

        dp = [[0] * (n + 1) for _ in range(m + 1)]
        # dp[i][j]表示text1[:i]与text[:j]的最长公共子序列长度

        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i - 1] == text2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                    res += text1[i - 1]
                else:
                    dp[i][j] = max([dp[i - 1][j], dp[i][j - 1]])
        print(res)
        return dp[m][n]

时间复杂度:O(mn)
空间复杂度:O(mn)

测试:

text1 = "abcde"
text2 = "ace"
obj = Solution()
res = obj.longestCommonSubsequence(text1, text2)
print(res)
# 3,最长公共子序列是ace
# ace 可以在计算dp的过程中保存得到

上面的代码中,dp只需要用到上一行i-1的结果,因此可以进行空间优化,只保存上一行以及当前行的结果。

class Solution:
    def longestCommonSubsequence_1(self, text1: str, text2: str) -> int:

        m = len(text1)
        n = len(text2)

        res = ""
        # 记录最长的公共子序列

        if m * n == 0:
            return 0

        dp = [[0] * (n + 1) for _ in range(2)]
        # dp[i][j]表示text1[:i]与text[:j]的最长公共子序列长度
        pre = 0
        cur = 1
        # pre存储上一行的结果,cur存储当前行结构
        # pre和cur在内存中的位置一会是第0行,一会是第1行

        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i - 1] == text2[j - 1]:
                    dp[cur][j] = dp[pre][j - 1] + 1
                    res += text1[i - 1]
                else:
                    dp[cur][j] = max([dp[pre][j], dp[cur][j - 1]])
            tmp = pre
            pre = cur
            cur = tmp

        print(res)
        return dp[pre][n]

时间复杂度:O(mn)
空间复杂度:O(2n)

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
最长公共子序列(Longest Common Subsequence,简称LCS)是指在两个序列中找到一个最长子序列,使得该子序列在两个序列中出现的顺序一致,但不要求连续。下面是一个用Python实现最长公共子序列的示例: ```python def longest_common_subsequence(seq1, seq2): m = len(seq1) n = len(seq2) # 创建一个二维数组来存储中间结果 dp = [[0] * (n+1) for _ in range(m+1)] # 填充二维数组,计算LCS的长度 for i in range(1, m+1): for j in range(1, n+1): if seq1[i-1] == seq2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) # 从二维数组中构建LCS lcs = [] i, j = m, n while i > 0 and j > 0: if seq1[i-1] == seq2[j-1]: lcs.append(seq1[i-1]) i -= 1 j -= 1 elif dp[i-1][j] > dp[i][j-1]: i -= 1 else: j -= 1 # 反转LCS得到最终结果 lcs.reverse() return lcs # 示例用法 seq1 = "ABCDGH" seq2 = "AEDFHR" lcs = longest_common_subsequence(seq1, seq2) print("Longest Common Subsequence:", "".join(lcs)) ``` 在这个示例中,我们定义了一个`longest_common_subsequence`函数,它接受两个序列`seq1`和`seq2`作为输入。函数使用动态规划的方法计算LCS的长度,并构建LCS序列。 在主程序中,我们使用示例输入序列`"ABCDGH"`和`"AEDFHR"`来测试`longest_common_subsequence`函数,并打印最长公共子序列。 运行上述代码,输出结果将是: ``` Longest Common Subsequence: ADH ``` 这表示序列`"ADH"`是`"ABCDGH"`和`"AEDFHR"`的最长公共子序列。 希望这个示例对你有帮助!如果你还有其他问题,请随时提问。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旺旺棒棒冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值