【科学刷题】最长公共子序列/子串(LCS)

1 最长公共子序列

1143. 最长公共子序列

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[i1,j1]+1max(c[i,j1],c[i1,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[i1,j1]+10i=0 or j=0xi=yjxi=yj

3 最长连续自增子串

674. 最长连续递增序列

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对应序列1j对应序列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. 两个字符串的删除操作

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)

712. 两个字符串的最小ASCII删除和

详解最长公共子序列问题,秒杀三道动态规划题目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值