1 最长公共子序列
c [ i , j ] = { 0 i = 0 or j = 0 c [ i − 1 , j − 1 ] + 1 i , j > 0 and x i = y j max ( c [ i , j − 1 ] , c [ i − 1 , j ] ) i , j > 0 and x i ≠ y j c[i, j]=\left\{\begin{array}{cc}0 & i=0 \text { or } \mathrm{j}=0 \\ c[i-1, j-1]+1 & i, j>0 \text { and } x_{i}=y_{j} \\ \max (c[i, j-1], c[i-1, j]) & i, j>0 \text { and } \mathrm{x}_{i} \neq y_{j}\end{array}\right. c[i,j]=⎩⎨⎧0c[i−1,j−1]+1max(c[i,j−1],c[i−1,j])i=0 or j=0i,j>0 and xi=yji,j>0 and xi=yj
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
l1 = len(text1)
l2 = len(text2)
dp = [[0] * (l2 + 1) for _ in range(l1 + 1)]
for i in range(1, l1 + 1):
for j in range(1, l2 + 1):
if text1[i - 1] == text2[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[-1][-1]
2 最长公共子串
【动态规划】最长公共子序列与最长公共子串
c
[
i
,
j
]
=
{
0
i
=
0
or
j
=
0
c
[
i
−
1
,
j
−
1
]
+
1
x
i
=
y
j
0
x
i
≠
y
j
c[i, j]=\left\{\begin{array}{cc} 0 & i=0 \text { or } \mathrm{j}=0 \\ c[i-1, j-1]+1 & x_{i}=y_{j} \\ 0 & x_{i} \neq y_{j} \end{array}\right.
c[i,j]=⎩⎨⎧0c[i−1,j−1]+10i=0 or j=0xi=yjxi=yj
3 最长连续自增子串
class Solution:
def findLengthOfLCIS(self, nums: List[int]) -> int:
n = len(nums)
dp = [1] * n
for i in range(1, n):
if nums[i] > nums[i - 1]:
dp[i] = dp[i - 1] + 1
return max(dp)
4 LCS的综合应用
我们来看一道微软的面试题,这道题需要面试者想出LCS的思路,然后处理一些LCS的综合问题,才能解出。
给两个分好词后的句子:
s1 = ['欢迎', '您', '面试', '.']
s2 = ['欢迎', '你', '来', '面试', '.']
要求将两者对齐,如果不能对齐则填充空格:
s1 = ['欢迎', '您', '', '', '面试', '.']
s2 = ['欢迎', '' ,'你', '来', '面试', '.']
首先求出LCS的dp矩阵:
s1 = ['欢迎', '您', '面试', '.']
s2 = ['欢迎', '你', '来', '面试', '.']
l1 = len(s1)
l2 = len(s2)
dp = [[0] * (l2 + 1) for _ in range(l1 + 1)]
for i in range(1, l1 + 1):
for j in range(1, l2 + 1):
if s1[i - 1] == s2[j - 1]: # 如果是公共元素
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j])
然后通过往上回溯,找出最长递增子序列:
i = l1
j = l2
LCS = []
while i > 0 and j > 0:
if s1[i - 1] == s2[j - 1]: # 如果是公共元素
LCS.append(s1[i - 1])
i -= 1
j -= 1
elif dp[i - 1][j] > dp[i][j - 1]: # 选dp值最大的路径
i -= 1
else:
j -= 1
LCS = LCS[::-1]
此时的 LCS = ['欢迎', '面试', '.']
用下标k
去遍历LCS
,并用i
对应序列1,j
对应序列2,每次遍历都让i,j
对齐
l3 = len(LCS)
ans1 = []
ans2 = []
i = 0
j = 0
for k in range(l3):
while i < l1 and s1[i] != LCS[k]:
i += 1
ans1.append(str(i))
ans2.append(' ')
while j < l2 and s2[j] != LCS[k]:
j += 1
ans2.append(str(j))
ans1.append(' ')
i += 1
j += 1
ans1.append(str(i))
ans2.append(str(j))
print(ans1)
print(ans2)
最后打印的结果:
['1', '2', ' ', ' ', '3', '4']
['1', ' ', '2', '3', '4', '5']
583. 两个字符串的删除操作
def longestCommonSubsequence(text1: str, text2: str) -> int:
l1=len(text1)
l2=len(text2)
dp=[[0]*(l2+1) for _ in range(l1+1)]
for i in range(1, l1+1):
for j in range(1, l2+1):
if text1[i-1]==text2[j-1]:
dp[i][j]=dp[i-1][j-1]+1
else:
dp[i][j]=max(dp[i][j-1],dp[i-1][j])
return dp[l1][l2]
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
return len(word1)+len(word2)-2*longestCommonSubsequence(word1,word2)