DP、哈希表、二分查找-718. 最长重复子数组

本文详细解析了求解两个数组间最长公共子数组及两个字符串间最长公共子串的动态规划算法。通过具体示例,阐述了如何初始化状态矩阵、设定状态转移方程,并更新最大值。适用于理解并解决LeetCode上相关问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、题目描述

https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/

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

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

2、代码详解

  1. dp初始化问题:dp实际是存储最大公共子串的默认值的数组,初始化为0,因为假设都是不存在重复子串嘛!
  2. 越界问题:但是要设置多少个0呢?我们考虑到i+1,所以必须设置为len(A)+1,这里有两个数组,故dp=[[0]*(len(B)+1) for _ in range(len(A)+1)],其实这可看作是矩阵的常用写法。
  3. 状态:dp为A和B的最长公共前缀,转移方程:dp[i+1][j+1]=dp[i][j]+1。在此之后(断开后)有可能会有更长的重复子串,故以result更新dp最大值,若是断开之后将会重新从0开始算,这就是初始化为啥要设为0了!!
  4. 模板:动态方程一般都采用dp[i+1][j+1]=dp[i][j]+1,dp[i+1][j+1]=max(dp[i][j-1],dp[i-1][j])等类似的形式,然后一般会用res=max(dp[i+1][j+1],res),存储最终结果。
class Solution(object):
    def findLength(self, A, B):
        """
        :type A: List[int]
        :type B: List[int]
        :rtype: int
        """
        m = len(A)
        n = len(B)
        dp = [[0]*(n+1) for _ in range(m+1)]
        res = 0
        for i in range(m):
            for j in range(n):
                if A[i] == B[j]:
                    dp[i+1][j+1] = dp[i][j] + 1
                    res = max(res, dp[i+1][j+1])
        # print(dp)
        return res

A = [1,2,3,2,1]
B = [3,2,1,4,7]
s = Solution()
print(s.findLength(A, B))

拓展(字符串,返回串和长度)

最长公共子串(The Longest Common Substring)  LCS问题就是求两个字符串最长公共子串的问题。

解法就是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。

然后求出对角线最长的1的序列,其对应的位置就是最长匹配子串的位置。

'''
两个字符串,求最长连续公共子串。
s1:abcxdkscad
s2:abkwkscawww
输出:ksca
'''
def func(s1, s2):
    len_1 = len(s1)
    len_2 = len(s2)
    dp = [[0 for _ in range(len_2+1)] for _ in range(len_1+1)]
    nmax = 0  # 最长匹配的长度
    p = 0  # 最长匹配对应在s1中的最后一位
    for i in range(len_1):
        for j in range(len_2):
            if s1[i] == s2[j]:
                dp[i+1][j+1] = dp[i][j] + 1
                if dp[i+1][j+1] > nmax:
                    nmax = dp[i+1][j+1]
                    p = i + 1
    print(dp)
    return s1[p-nmax:p], nmax  # 返回最长子串及其长度
s1 = 'abcxdkscad'
s2 = 'abkwkscawww'
print(func(s1, s2))  # ('ksca', 4)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值