📅  最后修改于: 2023-12-03 15:40:17.315000             🧑  作者: Mango
最长的公共子序列(Longest Common Subsequence, LCS)是一道经典的算法问题。给定两个字符串s1和s2,求它们的最长公共子序列。
先来解释一下什么是子序列。一个字符串的子序列是指该字符串通过删减某些字符(包括零个或全部)后得到的新字符串,例如字符串"abc"的子序列有"","a","b","c","ab","ac","bc","abc"。
下面再定义公共子序列。给定两个字符串s1和s2,一个字符串t是它们的公共子序列,如果t既是s1的子序列,又是s2的子序列,那么t就是s1和s2的公共子序列。
最长的公共子序列就是s1和s2的长度最长的公共子序列。
LCS问题可以使用递归和动态规划两种算法来求解。
递归算法的思路很简单,就是分别比较s1和s2的末尾字符是否相等,并且判断s1和s2去掉末尾字符的子字符串的LCS,再取两个LCS中长度更长的一个。递归算法的时间复杂度为O(2^n),n为s1和s2的长度之和。
def lcs(s1, s2):
if not s1 or not s2:
return ''
if s1[-1] == s2[-1]:
return lcs(s1[:-1], s2[:-1]) + s1[-1]
else:
l1 = lcs(s1[:-1], s2)
l2 = lcs(s1, s2[:-1])
return l1 if len(l1) > len(l2) else l2
动态规划算法是将递归算法中的重复计算缓存起来,避免重复计算,从而降低时间复杂度。LCS问题的动态规划解法通常使用二维数组来缓存计算结果。
先定义一个二维数组dp,dp[i][j]表示s1前i个字符和s2前j个字符的LCS的长度。当s1[i-1]==s2[j-1]时,dp[i][j] = dp[i-1][j-1]+1,否则dp[i][j] = max(dp[i-1][j], dp[i][j-1])。
def lcs(s1, s2):
m, n = len(s1), len(s2)
dp = [[0] * (n+1) for _ in range(m+1)]
for i in range(1, m+1):
for j in range(1, n+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])
return dp[m][n]
动态规划算法的时间复杂度为O(mn),m和n分别为s1和s2的长度。
最长的公共子序列是一道经典的算法问题,可以使用递归和动态规划两种算法来求解。递归算法简单易懂,但时间复杂度较高;动态规划算法复杂度较低,但需要理解动态规划的思想,并且需要定义一个二维数组来缓存计算结果。