【每日一题】LeetCode. 718. 最长重复子数组

每日一题,防止痴呆 = =

一、题目大意

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
【每日一题】LeetCode. 718. 最长重复子数组_第1张图片
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray

二、题目思路以及AC代码

思路一:动态规划

这是我一开始就想到的,也是自己写了AC代码的思路。我们可以直接设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,这样就可以在O(N*M)得复杂度内解决该题。

思路二:滑动窗口

因为做完这题就没再考虑了,看题解扩展思路得时候,看到了滑动窗口得方法。其思想就是我们如果把公共子数组得开始端对齐,那么我们就可以在O(N)得复杂度内找到最长得公共子数组得长度,那么我们可以先对所有对齐方式进行枚举,这样用到的时间复杂度是O(N + M),然后在每个对齐方式内,我们要用O(N)的时间复杂度找到最长公共子数组的长度,所以该方法的时间复杂度是O((N + M) * min(N, M)),应该是比思路一慢一点的,但是其空间复杂度为O(1)。

思路三:二分 + Hash

用这个方法的前提是,你得有一个Hash算法,可以支持你在O(N)的时间复杂度内对比两个子数组是否含有长度为len的公共子数组。其思想并不难,就是我们既然要求找到最长的公共子数组的长度,我们假设为k,那么我们一定有小于k的所有公共子数组长度,这样我们就可以二分了,举个例子,我们首先left = 0, right = len,然后mid = (left + right) >> 1,如果此时可以找到A和B长度为mid的公共子数组,那么说明现在这个mid长度还是小了,则要往右边找,否则往左边找。

AC代码

这里因为一开始就实现了DP的方法,这里就只有DP的代码了,后面两种只是看题解扩展一下思路而已。

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        int a_size = A.size();
        int b_size = B.size();

        int dp[a_size][b_size];
        for (int i=0;i<a_size;i++) {
            dp[i][0] = A[i]==B[0]?1:0;
        }
        for (int i=1;i<b_size;i++) {
            dp[0][i] = A[0]==B[i]?1:0;
        }

        int res = -1;
        for (int i=1;i<a_size;i++) {
            for (int j=1;j<b_size;j++) {
                if (A[i] == B[j]) dp[i][j] = dp[i-1][j-1] + 1;
                else dp[i][j] = 0;
                res = max(res, dp[i][j]);
            }
        }

        return res;
    }
};

如果有问题,欢迎大家指正!!!

你可能感兴趣的:(每日一题)