【LCStr】最长公共子串 / 【LCSeq】最长公共子序列 / 1035.【数组版本】不相交的线(Medium,=最长公共子序列)

最长公共子串

在这里插入图片描述

# longest common substring
# @param str1 string字符串 the string
# @param str2 string字符串 the string
# @return string字符串
#
class Solution:
	# 遍历版本,可返回子串 及 长度
    def LCS(self , str1 , str2 ):
        # 保证str1为短的一个字符串
        if len(str2) < len(str1):
            str1, str2 = str2, str1
            
        length, res = 0, ''
        
        # 遍历短的字符串的每一个字符,以此字符为结尾
        for i in range(len(str1)):
            if str1[i-length: i+1] in str2:
                res = str1[i-length: i+1] # 若出现更长的LCS,则更新LCS
                length += 1 # 若出现更长的LCS,则LCS长度加一
        
        return res, length
    
    # dp版本
    def LCStr(self, s1, s2):
	    '''最长公共子串'''
	    m, n = len(s1), len(s2)
	    # dp[i][j]表示以s1[i]与s2[j]为最后一个字符(s1[i]等于s2[j])的最长公共子串
	    dp = [[0] * n for _ in range(m)]
	    
	    res = 0
	    
	    for i in range(m):
	        for j in range(n):
	            if s1[i-1] == s2[j-1]: # 若当前两个字符相等,则长度加一
	                dp[i][j] = dp[i-1][j-1] + 1
	                res = max(res, dp[i][j])
	    
	    return res
	
	# 返回最长公共子串(dp版本)
	def LCStr(self, s1, s2):
	    '''最长公共子串'''
	    m, n = len(s1), len(s2)
	    # dp[i][j]表示以s1[i]与s2[j]为最后一个字符(s1[i]等于s2[j])的最长公共子串
	    dp = [[0] * n for _ in range(m)]
	
	    res = 0
	
	    for i in range(m):
	        for j in range(n):
	            if s1[i-1] == s2[j-1]: # 若当前两个字符相等,则长度加一
	                dp[i][j] = dp[i-1][j-1] + 1
	                if res < dp[i][j]:
	                    res = dp[i][j]
	                    lcs = s1[i-res: i] # or s2[j-res:j]
	
	    return res, lcs

最长公共子序列

在这里插入图片描述

在这里插入图片描述

class Solution:
	# 二维dp
	def LCSeq(s1, s2):
	    '''最长公共子序列'''
	    m, n = len(s1), len(s2)
	    # dp[i][j]表示截至到s1第i个字符与s2第j个字符的最长公共子序列
	    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[-1][-1]
    
    # 一维dp
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        if not text1 or not text2:
            return 0
            
        # dp = [[0 for _ in range(len(text2)+1)] for _ in range(len(text1)+1)]
        dp = [0 for _ in range(len(text2)+1)]
        for i in range(1, len(text1)+1):
            # 每遍历一个text1的字符,则初始化一个pre为0,
            # 表示以text1第i个字符与text2第j个字符结尾的最长公共子序列的长度
            pre = 0
            for j in range(1, len(text2)+1):
            	# 暂存上一轮text2以j-1结尾的最长公共子序列的长度
                temp = dp[j]          # temp = dp[j] = dp[i-1][j]
                # 更新本轮以text1第i个字符(固定不变)与text2第j个字符(变化)结尾的最长公共子序列的长度
                if text1[i-1] == text2[j-1]:
                    dp[j] = pre + 1
                else:
                    dp[j] = max(dp[j], dp[j-1])
                # 更新上一轮text2以j-1结尾的最长公共子序列的长度(防止下一个字符不相等)
                pre = temp
                
        return dp[-1]
  • 返回最长公共子序列
class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        m = len(text1)
        n = len(text2)

        dp = [[0] * (n+1) for _  in range(m+1)]
        g = [[0] * (n+1) for _  in range(m+1)]  # g用于存储转移的位置

        for i in range(1, m+1):
            for j in range(1, n+1):
                if text1[i-1] == text2[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                    g[i][j] = 1 # g中记录相同字符时的位置为1
                else:
                    if dp[i-1][j] > dp[i][j-1]:
                        dp[i][j] = dp[i-1][j]
                        g[i][j] = -1
                    else:
                        dp[i][j] = dp[i][j-1]
                        g[i][j] = 0
    
        #####################################
        ### 返回最长公共子序列
        stack=[]
        
        def trace(i,j):
            if i == 0 or j == 0: return
            
            if g[i][j] == 1:
                stack.append(text1[i-1])
                trace(i-1, j-1)
            elif g[i][j] == -1: # 选择返回寻找的移动方向
                trace(i-1, j)
            else:
                trace(i, j-1)
                
        if dp[-1][-1]: 
            trace(m, n)
        
        return ''.join(stack[::-1]), dp[-1][-1]              

最长公共子序列(字符串)

在这里插入图片描述

# longest common subsequence
# @param s1 string字符串 the string
# @param s2 string字符串 the string
# @return string字符串
#
class Solution:
    def LCS(self , s1 , s2 ):
        # write code here
        if not s1 or not s2: return -1
        
        res = ''
        max_len = 0
        
        # 保证s1为较短的串
        if len(s1) > len(s2):
            s1, s2 = s2, s1
            
        # 以每一个i结尾的公共子串及其长度
        for i in range(len(s1)):
            if s1[i-max_len:i+1] in s2:
                res = s1[i-max_len:i+1]
                max_len += 1
                
        return res if res else -1

1035. 不相交的线(Medium)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值