两种方法(滑动窗口, DP)解LeetCode水题:最长重复子数组

    技术2023-09-26  120

    目录

    题目

    解题思路

    滑动窗口

    ​思路

    代码

    结果

    DP

    思路

    代码

    结果


    今天下午休息,合租的小伙伴陪女票出去玩了,在家闲来无事就随便刷刷LeetCode每日一题吧,结果推送给我的是一道难度中等的题,这是在侮辱我的智商吗?可后面的解题过程告诉我,我智商不用它来侮辱也是负数。话不多说,上题目。

    题目

    给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。 示例: 输入: 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(n3),最后的提交结果也毫无意外地超时了。

    言归正传,再仔细阅读了一下题目,“公共的”、“长度最长的”这几个字眼再结合本题,不就在暗示我们用滑动窗口嘛。

    滑动窗口

    先上1张GIF图便于理解

    思路

    两个字符串分别为A串和B串

    1. 以A串为基准,B串向后滑动,每滑动一次比较两者公共部分(窗口)的元素,若连续相同则连续进行ret+1,若不同则ret不变。

    2. 以B串为基准,A串向后滑动,每滑动一次比较两者公共部分(窗口)的元素,若连续相同则连续进行ret+1,若不同则ret不变。

    3. 最后取两个ret最大值。

    代码

    public int findLength(int[] A, int[] B) { //滑动窗口 int res_num1=0,res_num2=0; //两次比较的两个结果,结果1和结果2 for(int i=0;i<A.length;i++) //以A串为基准,滑动B串 { int i_point=i,temp=0; for(int j=0;j<A.length-i;j++) //窗口大小为0~A.length-1 { if(B[j]==A[i_point]) //若窗口内元素相同,则temp+1,连续相同则temp连续+1 { temp += 1; res_num1 = Math.max(res_num1,temp); //不断和结果1比较大小 } else { temp=0; //若中间被打断,即窗口内A串和B串两个元素不同,那么temp归零。 } i_point++; //A串工作指针指向窗口内A串的下个元素 } } for(int i=0;i<B.length;i++) //以B串为基准,滑动A串 { int i_point=i,temp=0; for(int j=0;j<B.length-i;j++) { if(A[j]==B[i_point]) { temp+=1; res_num2 = Math.max(res_num2,temp); } else { temp=0; } i_point++; } } return Math.max(res_num1,res_num2); //返回最大值 }

    结果

     

    DP

    做完之后看了下题解,发现也可以用动态规划,而且这题用动态规划做还挺简单的,状态转移方程简单得一腿。

    思路

    令 dp[i][j] 表示 A[i:] 和 B[j:] 的最长公共前缀,那么答案即为所有 dp[i][j] 中的最大值。如果 A[i] == B[j],那么 dp[i][j] = dp[i + 1][j + 1] + 1,否则 dp[i][j] = 0。(这里借用了 Python 表示数组的方法,A[i:] 表示数组 A 中索引 i 到数组末尾的范围对应的子数组。)

    考虑到这里 dp[i][j] 的值从 dp[i + 1][j + 1] 转移得到,所以我们需要倒过来,首先计算 dp[len(A) - 1][len(B) - 1],最后计算 dp[0][0]。

    以题目中的输入为例

    A: [1,2,3,2,1] B: [3,2,1,4,7]

    状态转移方程为:

    若 A[i] != B[j] , dp[i][j] = 0 若 A[i] == B[j] , dp[i][j] = dp[i+1][j+1] + 1

    动态规划矩阵如下表所示:

     

     32147100100201000330000202000100100

    结果即为矩阵中的最大值3

    代码

    public int findLength(int[] A, int[] B) { //动态规划 int n = A.length, m = B.length; int[][] dp = new int[n + 1][m + 1]; int ans = 0; for (int i = n - 1; i >= 0; i--) { for (int j = m - 1; j >= 0; j--) { dp[i][j] = A[i] == B[j] ? dp[i + 1][j + 1] + 1 : 0; ans = Math.max(ans, dp[i][j]); } } return ans; }

    结果

    ————————————————————————————————————————

    烦躁啊,被疫情搞得左右为难,不知道怎么选择,到底出国还是国内还是HK还是工作,办CAS又被学校卡了,说要提供之前KCL Summer Course的CEFR/RQF Level证明,没有证明也要提供没有证明的证明,英国人办事真的死板,呵呵哒。。

    Processed: 0.012, SQL: 9