1. 程式人生 > >【演算法 in python | DP】LCS最長公共子串

【演算法 in python | DP】LCS最長公共子串

1. LCS,最長公共子串

動態規劃,狀態轉移方程:

Longest Common Subsequence Problem

#該版本是返回最長公共子串和其長度,若只返回長度,則可以簡化
def lcs(s1, s2):
    l1 = len(s1)
    l2 = len(s2)
    # res[i][j]儲存子串s1[0:i] 和 子串s2[0:j] 的lcs串
    # num[i][j]儲存子串s1[0:i] 和 子串s2[0:j] 的lcs長度
    #由於考慮到空串也作為比較元素,則將兩個字串的長度各加一
    res = [['' for i in range(l2+1)] for j in range(l1+1)]
    num = [[0 for i in range(l2+1)] for j in range(l1+1)]
    for i in range(1,l1+1):
        for j in range(1, l2+1):
            if s1[i-1] == s2[j-1]:
                num[i][j] = num[i-1][j-1]+1
                res[i][j] = res[i-1][j-1] + s1[i-1]
            else:
                if num[i-1][j] > num[i][j-1]:
                    num[i][j] = num[i-1][j]
                    res[i][j] = res[i-1][j]
                else:
                    num[i][j] = num[i][j-1]
                    res[i][j] = res[i][j-1]
    return num[-1][-1],res[-1][-1]

簡化版本:只返回最長LCS的長度。

def lcs(s1, s2):
    l1 = len(s1)
    l2 = len(s2)
    # num[i][j]儲存子串s1[0:i] 和 子串s2[0:j] 的lcs長度
    #由於考慮到空串也作為比較元素,則將兩個字串的長度各加一
    num = [[0 for i in range(l2+1)] for j in range(l1+1)]
    for i in range(1,l1+1):
        for j in range(1, l2+1):
            if s1[i-1] == s2[j-1]:
                num[i][j] = num[i-1][j-1]+1
            else:
                num[i][j] = max(num[i-1][j], num[i][j-1])
    return num[-1][-1]

2. 平方串

如果一個字串S是由兩個字串T連線而成,即S = T + T, 我們就稱S叫做平方串,例如"","aabaab","xxxx"都是平方串.
牛牛現在有一個字串s,請你幫助牛牛從s中移除儘量少的字元,讓剩下的字串是一個平方串。換句話說,就是找出s的最長子序列並且這個子序列構成一個平方串。 

即將s分成兩個子串,找出兩個子串的lcs,然後取最大的lcs的二倍。

def squreStr(s):
    #將s分成兩個子串,找出對應的lcs,在所有的lcs中找出最大的,其二倍即為對應的平方串的長度
    res = 0
    for i in range(1,len(s)):
        s1 = s[0:i]
        s2 = s[i:]
        res = max(res,lcs(s1,s2))
    return res*2