📅  最后修改于: 2023-12-03 15:42:13.228000             🧑  作者: Mango
本题目为 Gate CS Mock 2018 的第 46 题,属于计算机科学领域,需要解决的问题为如何实现线性时间求解最长公共子序列(LCS)问题。
给定两个字符串 S1 和 S2,写一个线性时间算法来查找它们之间的最长公共子序列(LCS)。
本题要求线性时间复杂度的解法,需要结合动态规划思想来求解最长公共子序列(LCS)问题。
我们可以建立一个二维数组 dp,其中 dp [ i ][ j ] 表示 S1[0:i] 和 S2[0:j] 之间的 LCS 长度。那么我们可以得到如下的递推式:
if s1[i] == s2[j]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
其中,如果 s1[i] == s2[j],表示当前位置匹配,那么 dp[i][j] 应该等于 dp[i-1][j-1] + 1;如果不匹配,那么 dp[i][j] 应该等于 dp[i-1][j] 和 dp[i][j-1] 中的较大值。
最终 DP 表格的右下角就是两个字符串的最长公共子序列的长度。
而最长公共子序列本身可以通过 DP 表格进行回溯获得,具体步骤为:
从 DP 表格的右下角开始,判断当前位置的字符是否相等。
如果相等,则说明这个字符是最长公共子序列中的一个字符,记录下来。
根据 DP 表格的递推式,有以下几种情况:
如果 dp[i-1][j] == dp[i][j],说明当前字符在 S1 中没有匹配到,需要向上回溯;
如果 dp[i][j-1] == dp[i][j],说明当前字符在 S2 中没有匹配到,需要向左回溯;
如果既不满足上面两个条件,说明当前字符既可以向上回溯,也可以向左回溯,可以任选其一。
重复步骤 1-3,直至回溯到 DP 表格的左上角。
可以看出,由于回溯的过程中涉及到多次查表和判断字符相等的操作,因此需要 O(m+n) 的时间复杂度。
以下是完整的 Python 代码实现:
def lcs(s1, s2):
# 创建 DP 表格
dp = [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)]
# 更新 DP 表格
for i in range(1, len(s1) + 1):
for j in range(1, len(s2) + 1):
if s1[i-1] == s2[j-1]: # 匹配
dp[i][j] = dp[i-1][j-1] + 1
else: # 不匹配
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
# 回溯解法
i, j = len(s1), len(s2)
lcs_str = ''
while i > 0 and j > 0:
if s1[i-1] == s2[j-1]:
lcs_str += s1[i-1]
i, j = i-1, j-1
elif dp[i-1][j] >= dp[i][j-1]:
i -= 1
else:
j -= 1
# 倒序输出最长公共子序列
return lcs_str[::-1]
至此,我们便完成了本题的代码实现。
最长公共子序列(LCS),GeeksforGeeks.
最长公共子序列(动态规划),阿靖~要做个好前端.
LintCode 77 最长公共子序列,胡云迪.