力扣718. 最长重复子数组
给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
示例 1:
输入:
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
分析
注意: 子数组是连续的,子序列可以不连续。
暴力法
对于a中的每个数字,在b中依次比较,如果相同,同步向后,不同就记录最大值。
时间复杂度O(N²)。 这个方法会超时。
动态规划
很容易发现,如果两个数字相同,并且他们俩前面的数字也相同,那么这个子数组的长度就可以加1。
我们用一个二维数组dp[i][j]来记录每一对ij对应的子数组的长度。
如果A[i]和B[j]不相等,那么这一对数据不构成公共子数组,所以赋值为0。
如果A[i]和B[j]相等,那么这一堆数据上面的公共子数组的长度就等于他们前面那一对数据的长度加1。所以得到了如下递推方程:
i>=1 && j>=1 时: dp[i][j] = A[i] == B[j]?dp[i-1][j-1]+1:0
i<1 || j<1 时: dp[i][j] = A[i] == B[j]?1:0
代码
class Solution {
public int findLength(int[] A, int[] B) {
//暴力解法
//对于a中的每个数字,在b中查找,找到后,同步向后,相同就继续往后走,不同就记录最大值。
// int maxLength = 0;
// for(int i = 0; i < A.length; i++){
// //暂存i
// for(int j = 0; j<B.length; j++){
// int tmpi = i;
// int tmpLen = 0;
// int tmpj = j;
// //找到第一个相同的数字
// while(tmpj<B.length && B[tmpj]!=A[i]) tmpj++;
// //往后比较
// while(tmpj<B.length && tmpi<A.length && B[tmpj] == A[tmpi]){
// tmpi++;
// tmpj++;
// tmpLen++;
// }
// maxLength = Math.max(tmpLen, maxLength);
// }
// }
// return maxLength;
//动态规划
int max = 0;
int[][] dp = new int[A.length][B.length];
for(int i = 0; i<A.length; i++){
for(int j = 0; j<B.length; j++){
if(A[i] == B[j]) {
if(i<1 || j<1){
dp[i][j] = 1;
}else {
dp[i][j] = dp[i-1][j-1]+1;
}
max = Math.max(max, dp[i][j]);
}
else dp[i][j] = 0;
}
}
return max;
}
}