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

来源:互联网 发布:微信矩阵是什么 编辑:程序博客网 时间:2024/06/03 12:10

【题目】

  给定两个字符串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,其余位置设为0。  
  2.矩阵的第一列。如果str1[i] == str2[0],dp[i][0]设为1,其余位置设为0。  
  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]
原创粉丝点击