递归与动态规划---最长公共子串问题

本文介绍了如何使用动态规划和递归解决最长公共子串问题。通过建立N×M的矩阵dp,根据字符匹配情况计算每个位置的最长子串长度。最终找到dp表中的最大值,从而确定最长公共子串。通过空间压缩,可以将空间复杂度降至O(1)。以Python3.5实现为例,详细解释了算法步骤。
摘要由CSDN通过智能技术生成

【题目】

  给定两个字符串str1和str2,返回两个字符串的最长公共子串。

【举例】

  str1 = “1AB2345CD”,str2 = “12345EF”,返回”2345”。

【基本思路】

  假设str1的长度为N,str2的长度为M,生成N×M的矩阵dp,dp[i][j]的含义是必须以str1[i]和str2[j]结尾的最长公共子串的长度,dp[i][j]的计算方法如下:

  1.矩阵的第一行。如果str1[0] == str2[j],此时以str1[0]和str2[j]结尾的最长公共子串就是它们自身,dp[0][j]设为1。 
  2.矩阵的第一列。如果str1[i] == str2[0],dp[i][0]设为1。  
  3. 矩阵的其它位置计算如下:
   1)如果str1[i] != str2[j],说明以str1[i]和str2[j]结尾的子串是不存在的,设为0。
   2) 如果str1[i] == str2[j],说明str1[i]和str2[j]可以作为公共子串的最后一个字符,从最后一个字符向左能扩多大的长度呢?就是dp[i-1][j-1]的值,所以dp[i][j] = dp[i-1][j-1] + 1。

  生成dp表之后,再得到最长的公共子串就很容易了。
  dp表中的最大值(假设为dp[x][y])就是最长公共子串的长度(假设为maxlen),str1中从下标x开始向左数的maxlen个字符就是最长的公共子串。

  因为dp[i][j]的值只依赖于dp[i-1][j-1],所以可以用空间压缩的方法将空间复杂度从O(N*M)降低到O(1)。

下面是用python3.5实现的代码

#最长公共子串问题
#经典动态规划方法。时间复杂度O(M*N),空间复杂度O(M*N)
def maxCommonSubStr(str1, str2):
    def getdp(str1, str2):
        dp = [[0 for i in range(len(str2))] for j in range(len(str1))]
        for i in range(len(str2)):
            if str2[i] == str1[0]:
                dp[0][i] = 1
        for i in range(len(str1)):
            if str1[i] == str2[0]:
                dp[i][0] = 1
        for i in range(1, len(str1)):
            for j in range(1, len(str2)):
                if str1[i] == str2[j]:
                    dp[i][j] = dp[i-1][j-1] + 1
        return dp


    if str1 == None or str2 == None or str1 == '' or str2 == '':
        return ""
    dp = getdp(str1, str2)
    length = 0
    index = 0
    for i in range(len(str1)):
        for j in range(len(str2)):
            if dp[i][j] > length:
                length = dp[i][j]
                index = i
    return str1[index-length+1 : index+1]

#动态规划升级版。时间复杂度O(M*N),空间复杂度O(1)
def maxCommonSubStr2(str1, str2):
    if str1 == None or str2 == None or str1 == "" or str2 == "":
        return ""
    maxlen = 0
    index = 0
    row = 0
    col = len(str2) - 1
    while row < len(str1):
        i = row 
        j = col
        length = 0
        while i < len(str1) and j < len(str2):
            if str1[i] == str2[j]:
                length += 1
            else:
                length = 0
            if length > maxlen:
                maxlen = length
                index = i
            i += 1
            j += 1
        if col > 0:
            col -= 1
        else:
            row += 1
    return str1[index-maxlen+1 : index+1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值