最長公共子序列LCS理解和實現[python]

問題:給定兩個字符串S1和S2,求這兩個字符串的最長公共子序列的長度
例子:
    S1= ABCD,S2=AEBD,最長公共子序列長度爲3
思路:
    1.自頂向下的方法

        |-回溯法: 時間複雜度O(2^n * n)
            |-對兩字符串的最後一個字符進行比較,分爲相等和不相等兩種情況
                |-相等:res = 1 + back(m-1, n-1)
                |-不相等:res = max(back(m, n-1), back(m-1, n))
                |-其中m,n分別爲兩個字符串的最後一個元素的索引,back爲遞歸調用的尋找最長公共子序列的函數
        |-結構化子函數:時間複雜度O(m*n)
    2.自底向上的方法
        |-二維的動態規劃:
            |-狀態LCS(m, n):表示S1[0...m]和S2[0...n]的最長公共子序列的長度
            |-m, n 爲LCS中新增加的兩個字符,我們只需要考慮當前新增這兩個字符後的狀態轉移即可。
            |-狀態轉移方程分爲兩種情況:
                |-1. S1[m] == S2[n]: LCS(m, n)=1+LCS(m-1,n-1)
                |-2. S1[m] != S2[N]: LCS(m, n)=max(Lcs(m-1, n), LCS(m, n-1))

            |-時間複雜度O(m*n)

github: 點擊打開鏈接

python源代碼:

class Solution(object):
    # 1 回溯法
    def back(self, S1, S2):
        m = len(S1)-1
        n = len(S2)-1
        # 終止條件
        if m < 0 or n < 0:
            return 0
        # 遞歸過程
        if S1[m] == S2[n]:
            return 1+self.back(S1[:m], S2[:n])
        else:
            # 不相等
            return max(self.back(S1[:m], S2), self.back(S1, S2[:n]))

    # 2 結構化子函數
    def childS(self, S1, S2):
        m = len(S1) - 1
        n = len(S2) - 1
        rows = [-1 for i in range(n + 1)]
        memo = [rows.copy() for j in range(m + 1)]
        return self.struct(S1, S2, memo)
    def struct(self, S1, S2, memo):
        m = len(S1) - 1
        n = len(S2) - 1
        # 終止條件
        if m < 0 or n < 0:
            return 0

        if S1[m] == S2[n]:
            if memo[m-1][n-1] == -1:
                memo[m - 1][n - 1] = self.struct(S1[:m], S2[:n], memo)+1
            return memo[m-1][n-1]
        else:
            if memo[m-1][n] == -1:
                memo[m - 1][n] = self.struct(S1[:m], S2, memo)
            if memo[m][n-1] == -1:
                memo[m][n - 1] = self.struct(S1, S2[:n], memo)
            return max(memo[m][n - 1], memo[m-1][n])

    # 3 動態規劃
    def dp(self, S1, S2):
        m = len(S1)
        n = len(S2)
        if m < 0 or n < 0:
            return 0
        memo = [[0]*(n+1) for j in range(m+1)]
        # 初始狀態 第0行 第0列 都是0
        for i in range(1, m+1):
            for j in range(1, n+1):
                if S1[i-1] == S2[j-1]:  # S1中的第i個字符 S2中的第j個字符
                    memo[i][j] = 1 + memo[i-1][j-1]
                else:
                    memo[i][j] = max(memo[i-1][j], memo[i][j-1])
        return memo[m][n]

S1 = 'AFDSAFDSA'
S2 = 'FDSAFD'
print(Solution().dp(S1, S2))class Solutio

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章