题目
给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
解法
本文在官方题解的基础上加了一点解释,作为补充,建议与力扣官方题解一起观看
1. 动态规划
1.1 思路
dp[i][j]
表示nums1[i...end]
与nums2[j...end]
的最长公共前缀部分的长度
如果 nums1[i]
== nums2[j]
,那么 dp[i][j]
= dp[i + 1][j + 1]
+ 1
如果 nums1[i]
!= nums2[j]
,那么前缀部分肯定是不相同的,所以 dp[i][j]
= 0
在这个过程中记录下dp数组的最大值即可,即 res
因为dp[i][j]
是从dp[i + 1][j + 1]
转移而来的,所以要倒着遍历数组
1.2 代码
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
int dp[][] = new int[n + 1][m + 1];
int res = 0;
for (int i = n - 1; i >= 0; i--) {
for (int j = m - 1; j >= 0; j--) {
dp[i][j] = nums1[i] == nums2[j] ? dp[i + 1][j + 1] + 1 : 0;
res = Math.max(res, dp[i][j]);
}
}
return res;
}
}
1.3 复杂度
- 时间复杂度:
O(m*n)
- 空间复杂度:
O(m*n)
2. 滑动窗口
2.1 思路
两种对齐方式,一种是让A数组的开头产生偏移量,使得B数组的首个元素与A数组的某个元素对齐
,另一种则是让B数组的开头产生偏移量,使得A数组的首个元素与B数组的某个元素对齐
2.2 代码
class Solution {
public int findLength(int[] A, int[] B) {
int n = A.length, m = B.length;
int res = 0;
// A的开头增加偏移量,偏移量大小为i,让B的首元素跟A的某个元素进行“对齐”
for (int i = 0; i < n; i++) {
int len = Math.min(n - i, m); // 滑动窗口大小,最小为1
int maxLen = maxLength(A, i, B, 0, len);
res = Math.max(res, maxLen);
}
// B的开头增加偏移量,偏移量大小为j,让A的首元素跟B的某个元素进行“对齐”
for (int j = 0; j < m; j++) {
int len = Math.min(n, m - j); // 滑动窗口大小,最小为1
int maxLen = maxLength(A, 0, B, j, len);
res = Math.max(res, maxLen);
}
return res;
}
public int maxLength(int[] A, int offsetA, int[] B, int offsetB, int len) {
int res = 0, k = 0;
// 在滑动窗口内逐个比较两个数组的元素,如果相同则k++,如果不同则k退回为0,在此过程中记录最大的k的值
for (int i = 0; i < len; i++) {
if (A[offsetA + i] == B[offsetB + i]) {
k++;
}else {
k = 0;
}
res = Math.max(res, k);
}
return res;
}
}
代码图示
2.3 复杂度
- 时间复杂度:
O(m+n)*min(n,m)
,近似方法1中的O(m*n)
- 空间复杂度:
O(1)