1006 最长公共子序列Lcs
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
比如两个串为:
abcicba
abdkscab
ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。
Input
第1行:字符串A
第2行:字符串B
(A,B的长度 <= 1000)
Output
输出最长的子序列,如果有多个,随意输出1个。
Input示例
abcicba
abdkscab
Output示例
abca
解题思路:
对与求最长公共子序列、最长递增子序列等问题,都用动态规划来解即可,本题也不列外。
最长公共子序列的动态转移方程为:
当A[i] = B[j]时,f(i, j) = f(i-1, j-1)+1
当A[i] != B[j]是,f(i, j) = max(f(i-1, j), f(i, j-1))
当i=0,j=0的时候,进行i-1, j-1操作,会变为-1,看上去可能会出错。但是python不一样,列表里如果索引为负数,那么是为反向索引列表,即-1索引值为列表的最后一个数。
当然,本题最麻烦的地方是,什么时候输出的子序列是最长的。这个可以通过得到的动态转移的方程值进行回溯操作,具体可以看如下代码:
while True:
try:
A = input()
B = input()
la, lb = len(A), len(B)
#初始化动态转移方程列表,这样可以造出像C语言那般的二维数组
f=[[0 for i in range(la+1)] for j in range(lb+1)]
#进行动态转移
for i in range(la):
for j in range(lb):
if A[i] == B[j]:
f[i][j] = f[i-1][j-1] + 1
else:
f[i][j] = max(f[i-1][j], f[i][j-1])
i, j, k= la-1, lb-1, 0
#ans可以看作是一个栈,因为回溯得到的子序列是反向的
#我们把子序列压入栈中可以反向输出子序列
ans = []
#下面是利用得到的最大f[i][j]进行回溯操作
while i>=0 and j>=0:
if A[i] == B[j]:
ans.append(A[i])
i, j = i-1, j-1
elif f[i-1][j] > f[i][j-1]:
i -= 1
else:
j -= 1
#输出操作
while len(ans):
print(ans.pop(), end='')
print()
except EOFError:
break
这题代码我是以C语言改编而来,运行的时候,python比C慢的缺陷很快便体现出来了,此题C语言所花的时间仅仅只有两位数,但python花的时间到四位数。python慢归慢,但是有的时候确实比C方便实用。