最长公共子串
# 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