基礎算法五:最長公共子序列問題

計算字符串a和b之間的最長公共子序列(LCS),同樣是一個動態規劃問題。我們需要分兩步解決這個問題。首先,我們要找到字符串a和b之間的最長公共子序列的長度。然後通過逆序查找找到最長公共子序列。

我們用table[i][j]表示字符串a[1:i],b[1:j]之間的最長公共子序列的長度。很顯然如果a[i]等於b[j],table[i][j]等於table[i-1][j-1]+1。如果a[i]不等於b[j],table[i][j]等於table[i][j-1]和table[i-1][j]中較大的值。於是動態規劃方程可以寫爲:

然後我們將思路反過來,根據生成的二維數組table反向查找最長公共子序列。整體代碼如下:

def LCS(a, b):
    table = lcs_table(a, b)
    lcs = lcs_generate(table, a, len(a), len(b))
    return lcs


def lcs_table(a, b):
    '''
    計算最長公共子序列長度
    '''
    table = [[0 for j in range(len(b) + 1)] for i in range(len(a) + 1)]
    for i in range(len(a) + 1)[1:]:
        for j in range(len(b) + 1)[1:]:
            if a[i - 1] == b[j - 1]:
                table[i][j] = table[i - 1][j - 1] + 1
            else:
                table[i][j] = max(table[i - 1][j], table[i][j - 1])
    return table


def lcs_generate(table, a, i, j):
    '''
    生成最長公共子序列
    '''
    if table[i][j] == 0:
        return ''
    if table[i - 1][j] == table[i][j]:
        return lcs_generate(table, a, i - 1, j)
    elif table[i][j - 1] == table[i][j]:
        return lcs_generate(table, a, i, j - 1)
    else:
        return lcs_generate(table, a, i - 1, j - 1) + a[i - 1]


if __name__ == '__main__':
    a = 'ABCBDAB'
    b = 'BDCABA'
    print(LCS(a, b))

結果爲:

BCBA

 

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