最长公共子序列和最长公共子串

基本概念

首先,需要搞清楚这是两个不一样的问题,序列要求可以不是连续的,而子串要求必须是连续的。
下面我们将来介绍两个问题的解法,我们采用的方法是以空间换时间的动态规划的问题,对于动态规划,如何写出状态转移方程是问题求解的关键,还需要我们找出问题的起始解是什么。对于一些比较难得问题,我们无法直接应用动态规划,需要做一些变换(其中大部分是数学的思想)

最长公共子串

X=<x1,x2,x3......xn> ,Y=<y1,y2,y3......yn>
首先,我们先写出一个最简单的方法,状态转移方程为:
record[i][j] = record[i-1][j-1]+1
i,j表示以xi和yj结尾的最长公共子串,具体代码如下:

class Solution:
    def LongestCommonSubstring(self,text,query):
        record = [[0 for i in range(len(query)+1)] for j in range(len(text)+1)]
        record[0][0]=0
        res,index = 0,0
        for i in range(0,len(text)):
            for j in range(0,len(query)):
                if text[i]==query[j]:
                    record[i][j] = record[i-1][j-1]+1
                else:
                    record[i][j] = 0
                if res<record[i][j]:
                    res=record[i][j]
                    index=i
        return res,text[index-res+1:index+1]

if __name__ =="__main__":
    s = Solution()
    text,query = "acaccbabb","acbac"
    print s.LongestCommonSubstring(text,query)

上述揭发时间复杂度和空间复杂度均为为O(len(text)*len(query)),按常理,动态规划的空间复杂度是可以优化到1维数组的,需要逆序便利,为什么逆序,
具体如下:

class Solution:
    def LongestCommonSubstring(self,text,query):
        record = [0 for i in range(len(text)+1)]
        res,index = 0,0
        for i in range(len(query)):
            for j in range(len(text)-1,0,-1):
                if query[i]==text[j]:
                    record[j] = record[j-1]+1
                else:
                    record[j] = 0
                if res<record[j]:
                    res=record[j]
                    index=j
        return res,text[index-res+1:index+1]


if __name__ =="__main__":
    s = Solution()
    text,query = "acaccbabb","acbac"
    print s.LongestCommonSubstring(text,query)

最长公共子序列

相对于上一个问题,这个问题更难一点,首先还是要写出状态转移方程:

         if text[i-1]==query[j-1]:
              record[i][j]=record[i-1][j-1]+1
         else:                   
             record[i][j] = max(record[i-1][j],record[i][j-1])

代码如下:

class Solution:
    def LongestCommonSubSequeence(self,text,query):
        record = [[0 for j in range(len(query)+1)] for i in range(len(text)+1)]
        for i in range(len(text)+1):
            record[i][0] = 0
        for j in range(len(query)+1):
            record[0][j] = 0
        for i in range(1,len(text)+1):
            for j in range(1,len(query)+1):
                if text[i-1]==query[j-1]:
                    record[i][j]=record[i-1][j-1]+1
                else:
                    record[i][j] = max(record[i-1][j],record[i][j-1])
        return record[len(text)][len(query)]

if __name__ =="__main__":
    s = Solution()
    text,query = "acaccbabb","acbac"
    print s.LongestCommonSubSequeence(text,query)   

以上就是最长公共子串与最长公共子序列的解法

推荐阅读更多精彩内容