算法:最长重复子数组【动态规划】

最长重复子数组/最长公共子串

题目描述:

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。

示例 1:

输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出: 3
解释:
长度最长的公共子数组是 [3, 2, 1]。
说明:

1 <= len(A), len(B) <= 1000
0 <= A[i], B[i] < 100

LeetCode

分析:

  • 要求公共子数组/子串,可以用dp
  • 构建dp数组,dp[i][j]表示必须把A[i]和B[j]作为公共子数组最后一个元素时,公共子数组的最大长度
  • 第一行和第一列:A[i]和B[j]相等为1,不等为0
  • 其他位置:A[i] == B[j],则dp[i][j] = dp[i-1][j-1] + 1,否则dp[i][j] = 0
  • 此方法时间和空间复杂度均为O(N*M)

优化

  • 由于计算dp[i][j]只需要dp[i-1][j-1]的值,因此可以定义变量来存储该值

算法:最长重复子数组【动态规划】_第1张图片
算法:最长重复子数组【动态规划】_第2张图片

# 分别用dp二维数组(空间O(M*N))和变量(空间O(1))做
def opt(A, B):
    row = 0
    col = len(A)-1
    max_len = 0  # 记录最大长度
    end = 0  # 记录最大长度子串的结束位置

    while row < len(B):
        i = row
        j = col
        leng = 0
        while i < len(B) and j < len(A):
            if A[j] == B[i]:
                leng += 1
            else:
                leng = 0
            if leng > max_len:
                max_len = leng
                end = i
            i += 1
            j += 1
        # 列向左移动到最左后,行再往下走
        if col > 0:
            col -= 1
        else:
            row += 1
    
    return max_len
        


def dp(A, B):
    dp = [[0] * len(A) for _ in range(len(B))]
    for i in range(len(A)):
        if A[i] == B[0]:
            dp[0][i] = 1
    for i in range(len(B)):
        if B[i] == A[0]:
            dp[i][0] = 1
    result = 0
    
    for i in range(1, len(B)):
        for j in range(1, len(A)):
            if B[i] == A[j]:
                dp[i][j] = dp[i-1][j-1] + 1
                # print(i,j,dp[i][j])
                result = dp[i][j] if dp[i][j] > result else result
    return result


class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        # return dp(A, B)
        return opt(A, B)
        

你可能感兴趣的:(算法)