計算字符串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