0
点赞
收藏
分享

微信扫一扫

LeetCode 718. 最长重复子数组



文章目录

  • ​​题目描述​​
  • ​​动态规划​​
  • ​​滑动窗口​​

题目描述

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

动态规划

两个数组,找公共子数组。第一思路是动态规划,设​​f[i,j]​​​表示在​​nums1​​​中以位置​​i​​​结尾,​​nums2​​​中以位置​​j​​结尾,的全部公共子数组中,长度最大的公共子数组的长度。

  • 当​​nums1[i] != nums2[j]​​​,很明显不存在公共子数组,故​​f[i,j] = 0​
  • 当​​nums1[i] == nums2[j]​​​,存在公共子数组,​​f[i,j] = f[i - 1, j - 1] + 1​
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
int[][] f = new int[n + 1][m + 1];
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (nums1[i - 1] == nums2[j - 1]) {
f[i][j] = f[i - 1][j - 1] + 1;
ans = Math.max(ans, f[i][j]);
}
}
}
return ans;
}
}

优化:观察可以知道​​f[i][j]​​的状态,只取决于其左上角的状态(上一行的左侧那个位置),则可以用滚动数组的思想,优化为一维。(每一行状态的更新,从右往左)

class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
int[] f = new int[m + 1];
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = m; j >= 1; j--) {
if (nums1[i - 1] == nums2[j - 1]) {
f[j] = f[j - 1] + 1;
ans = Math.max(ans, f[j]);
} else {
f[j] = 0; // 需要还原为0
}
}
}
return ans;
}
}

动规的时间复杂度是 ,空间复杂度是

滑动窗口

最长重复子数组,一定是将两个数组在某个位置上对齐,之后在重合的区间内,能够得到的最长的子数组。枚举所有的对齐方式,然后判断此时重合区间内的重复子数组的长度即可。

class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
int ans = 0;
for (int i = m - 1; i >= 0; i--) {
ans = Math.max(ans, getMaxLen(nums1, 0, nums2, i));
}

for (int i = 1; i < n; i++) {
ans = Math.max(ans, getMaxLen(nums1, i, nums2, 0));
}

return ans;
}

private int getMaxLen(int[] nums1, int i, int[] nums2, int j) {
int n = nums1.length, m = nums2.length;
int len = 0, maxLen = 0;
while (i < n && j < m) {
if (nums1[i] == nums2[j]) {
len++;
} else {
maxLen = Math.max(maxLen, len); // 断掉了, 记录答案
len = 0; // 重置
}
i++;
j++;
}
// 最后一次的len
maxLen = Math.max(maxLen, len);
return maxLen;
}
}

时间复杂度 ,空间复杂度



举报

相关推荐

0 条评论