【20190914】【每天一道算法题】最长重复子数组(二分法、动态规划)

问题

给两个整数数组 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


思路及解答

# 方法一:暴力法(超时)
# 时间复杂度:O(n * m * min(n,m))
class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        result = 0
        for i in range(len(A)):
            for j in range(len(B)):
                for k in range(1, min(len(A), len(B))+1-j):   # 这里加了k不能超过数组长度!不然会出错!
                    if A[i:i + k] == B[j:j + k]:
                        result = k if k > result else result
                    else:
                        break
        return result
		
		
# 方法二:二分查找(left,right分别初始化为0,min(len(A), len(B)),mid是输入到seen函数里的length,如果没有mid长度的,则长度往下找;若有mid长度的,那么mid长度再往上找,看是否存在比mid更长的长度)
# 时间复杂度:O((m*n) * min(m,n)log(min(m,n)))
# 超时

# 该函数判断两个字符串A和B是否存在length长度的公共子序列!!!
def seen(A, B, length):
    for i in range(len(A)-length+1):
        for j in range(len(B)-length+1):
            # if A[i: min(i+length, len(A))] == B[j: min(j+length, len(B))]:   # 这句保证不了length的长度!!!
            if A[i: i+length] == B[j: j+length]:
                return True
    return False

class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        result = 0
        left, right = 0, min(len(A), len(B))
        mid = (left + right) // 2
        while left <= right:
            if seen(A, B, mid):
                result = mid if result < mid else result
                left = mid + 1
                mid = (left + right) //2
            else:
                right = mid - 1
                mid = (left + right) //2
        return result
		
		
# 方法三:动态规划(一步步调试之后我发现,原理就是确定一个被比较的字符串,例如这里是A,那么用B和它进行比较,j开始循环,若A[i]==B[j],那么说明这个相等,那么dp[i][j]=dp[i+1][j+1]+1,否则dp[i][j]=0,画出来就是对角线加一那个。。。)
# 时间复杂度:O(m*n)
class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        dp = [[0] * (len(B)+1) for _ in range(len(A)+1)]
        for i in range(len(A) - 1, -1, -1):
            for j in range(len(B) - 1, -1, -1):
                if A[i] == B[j]:
                    dp[i][j] = dp[i + 1][j + 1] + 1
                else:
                    dp[i][j] = 0
        # return max(dp[i][j] for i in range(len(A)) for j in range(len(B)))
        return max(max(row) for row in dp)
		
# 我重写的(从后往前比较,换一下循环顺序)
class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        dp = [[0] * (len(A) + 1) for _ in range(len(B) + 1)]   # 注意这里的顺序和后面两个for的顺序对应
        for i in range(len(B)-1, -1, -1):
            for j in range(len(A)-1, -1, -1):
                if A[j] == B[i]:
                    dp[i][j] = dp[i+1][j+1] + 1
                else:
                    dp[i][j] = 0
        return max(dp[i][j] for i in range(len(B)) for j in range(len(A)))
		
# 我重写的(从前往后比较)
class Solution:
    def findLength(self, A: List[int], B: List[int]) -> int:
        dp = [[0] * (len(A) + 1) for _ in range(len(B)+1)]   # dp有len(B)+1行
        for i in range(1, len(B)+1):
            for j in range(1, len(A)+1):
                if A[j-1] == B[i-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = 0
        return max(max(row) for row in dp)

知识点

1. Python 中 max() 和 min() 的使用(注意列表和矩阵的区别!!!)

(1) 列表:如果是嵌套列表,那么输出的是子列表首元素较大的那个,若首元素相同,那么往后比较;

(2) 矩阵:max(0)/min(0) 返回矩阵每一列的最大/小值;max(1)/min(1) 返回矩阵每一行的最大/小值。

列表变矩阵要用 np.array(List)命令。

(参考:怎样在二维列表中使用max函数

(参考:python Numpy中的min(),max()函数

(参考:Python内置函数max()高级用法

(参考:min(0),max(0) python 矩阵中的用法

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Satisfying

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值