LeetCode 718. 最长重复子数组

99 阅读1分钟

1. 题目

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

示例 1:

输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。
示例 2:

输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0]
输出:5

提示:

1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 100

来源:力扣(LeetCode)
链接:leetcode.cn/problems/ma…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 思路

动态规划,dp[i][j] 表示以 nums1[i] 开始 和 以 nums2[j] 开始的最长公共子数组的长度,初始时,dp[nums1.length - 1][nums2.length - 1] = nums1[nums1.length - 1] == nums2[nums2.length - 1] ? 1 : 0,因此动态转移方程可写为 dp[i][j] = nums1[i] == nums2[j] ? dp[i + 1][j + 1] + 1 : 0,考虑到数组边界情况,可以将动态规划数组的长度增加1

3. 优化

dp[i][j] 只与 dp[i + 1][j + 1] 有关,因此可以用两个一维数组保存状态

4. 代码

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;
        int[] dp1 = new int[n + 1], dp2 = new int[n + 1];
        int res = 0;
        for (int i = m - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                if (i % 2 == 0) {
                    dp1[j] = nums1[i] == nums2[j] ? dp2[j + 1] + 1 : 0;
                    res = Math.max(dp1[j], res);
                } else {
                    dp2[j] = nums1[i] == nums2[j] ? dp1[j + 1] + 1 : 0;
                    res = Math.max(dp2[j], res);
                }
            }
        }
        return res;
    }
}

5. 最后,看下是否通过

image.png

6. 还有一种优化,使用一个一维数组即可

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;
        int[] dp = new int[n + 1];
        int res = 0;
        int pre = 0, temp = 0;
        for (int i = m - 1; i >= 0; i--) {
            pre = 0;
            for (int j = n - 1; j >= 0; j--) {
                temp = dp[j];
                dp[j] = nums1[i] == nums2[j] ? pre + 1 : 0;
                res = Math.max(dp[j], res);
                pre = temp;
            }
        }
        return res;
    }
}

7. 容易混淆的地方

有一道题是最长公共子序列 1143. 最长公共子序列,公共子序列那道题中不要求子串连续,而最长重复子数组的题要求子序列连续