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