力扣 718.最长重复子数组

问题描述

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

示例:

输入:
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

问题思路

思路1:暴力法

对两个数组的起始位置的所有情况进行遍历,计算每种情况下的最长相同子数组的长度。

实现代码如下,空间复杂度O(1),时间复杂度O(n^3)。运行时间2740 ms。

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;
        int out = 0;
        for(int i = 0; i < n1; i++){
            for(int j = 0; j < n2; j++){
                int len = 0;
                while(i + len < n1 && j + len < n2 
                && nums1[i+len] == nums2[j+len]){
                    len++;
                }
                out = Integer.max(out, len);
            }
        }
        return out;
    }
}
思路2:动态规划法

观察思路1,发现有很多重复计算,考虑用动态规划减少重复计算次数。

进一步发现,从起始位置分别为 i, j 的最长相同子数组的长度 l(i,j) 满足:当 nums1[i] = nums2[j] 时,l(i,j) = l(i+1, j+1) + 1 ,否则 l(i, j) = 0。

由此递推式即可使用动态规划求解。

实现代码如下,空间复杂度O(mn),时间复杂度O(n^2)。运行时间46 ms。

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;
        int out = 0;
        for(int i = 0; i < n1; i++){
            for(int j = 0; j < n2; j++){
                int len = 0;
                while(i + len < n1 && j + len < n2 
                && nums1[i+len] == nums2[j+len]){
                    len++;
                }
                out = Integer.max(out, len);
            }
        }
        return out;
    }
}
思路3:滑动窗口法

其实比较得到最大长度,如果再加上一个条件:相同元素的下标位置一定相同,那么问题就变得非常简单,样例伪代码:

int len = 0;
int out = 0;
for(int i = 0; i < minleng; i++){
	if(nums1[i] == nums2[i]){
		len++;
		out = Integer.max(out, len);
	}else{		
		len = 0;
	}
}

为了能满足这个条件,我们可以分别对某个数组的偏移量进行遍历,这样就得到所有对齐方式,然后对每个对齐方式进行计算,就可以得到最大长度。

实现代码如下,空间复杂度O(1),时间复杂度O((m+n)*min(m,n))。运行时间57 ms。

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int n1 = nums1.length;
        int n2 = nums2.length;
        int out = 0;
        for(int i = 0; i < n1; i++){
            int len = sublength(nums1, nums2, i, 0, Integer.min(n2, n1 - i));
            out = Integer.max(out, len);
        }
        for(int i = 0; i < n2; i++){
            int len = sublength(nums1, nums2, 0, i, Integer.min(n1, n2 - i));
            out = Integer.max(out, len);
        }
        return out;
    }
    public int sublength(int[] nums1, int[] nums2, int adda, int addb, int n){
        int len = 0;
        int out = 0;
        for(int i = 0; i < n; i++){
	        if(nums1[i+adda] == nums2[i+addb]){
		        len++;
		        out = Integer.max(out, len);
	        }else{
		        len = 0;
	        }
        }
        return out;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值