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. 最后,看下是否通过
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. 最长公共子序列,公共子序列那道题中不要求子串连续,而最长重复子数组的题要求子序列连续