以1143. 最长公共子序列、718. 最长重复子数组为例
题目
子序列和子数组
- 子序列:由数组中不连续的元素组成的数组。eg:[1, 2, 3, 4]子序列可为[1, 4]
- 子数组:数组中连续元素组成的数组。eg:[1, 2, 3, 4]子数组可以为[1, 2, 3]
代码实现
两者的代码非常相似
"""
最长公共子数组(连续)- 动态规划
"""
class Solution:
def findLength(self, A, B) -> int:
dp, res = [[0] * (len(B)+1) for _ in range(len(A)+1)], 0
for i in range(1, len(A)+1):
for j in range(1, len(B)+1):
if A[i-1] == B[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
if dp[i][j] > res:
res = dp[i][j]
return res
其中718. 最长重复子数组也可以采用滑动窗口来做,运行速度要比动态规划快一些。
"""
最长公共子数组 - 滑动窗口
其中判断一个序列是否在另一个序列中可以采用转换为字符串再进行比较
转换成字符串的时候需要注意:
因为可以能出现 "3,53" in "23,53"这种情况,所以数字的前后也要加上分隔符
"""
class Solution:
def findLength(self, A, B) -> int:
if not (set(A) & set(B)):
return 0
A = ","+",".join(list(map(str, A)))+","
B = list(map(str, B))
l, r, res = 0, 0, 1
while l <= r and r < len(B):
# 不断扩大符合条件的子串
while r < len(B) and ","+",".join(B[l:r+1])+"," in A:
res = max(res, r - l + 1)
r += 1
# 缩小子串
while l < r and not ","+",".join(B[l:r+1])+"," in A:
l += 1
if r <= l:
r = l + 1
return res
"""
最长公共子序列(不连续)
"""
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
dp = [[0] * (len(text2)+1) for i in range(len(text1)+1)]
for i in range(1, len(text1)+1):
for j in range(1, len(text2)+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[len(text1)][len(text2)]