给两个整数数组 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
思路:
采用动态规划,通过维护一个二维数组dp来计算最长重复子数组。如下图例子所示:
3 1 2
1 0 1 0
2 0 0 2
2 0 0 1
行表示A,列表示B,dp[i][j]的值为如果A[i]和B[j]相等,则dp[i][j]等于他左上角的值+1,否则等于0。
参考代码如下:
int findLength(vector<int>& A, vector<int>& B) {
int m = A.size();
int n = B.size();
if (!m || !n) {
return 0;
}
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
int res = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = (A[i - 1] == B[j - 1]) ? dp[i - 1][j - 1] + 1 : 0;
res = max(res, dp[i][j]);
}
}
return res;
}
思路2:本文可以简化为O(n+1)的复杂度,即只需要一个一维数组,由于我们要考虑到数组元素覆盖的问题,所以递归公式改为:
/**
* dp[i][j] = a[i] == b[j] ? dp[i + 1][j + 1] : 0;
* dp[i][j] : max lenth of common subarray start at a[i] & b[j];
*/
且遍历A和B的方式发生了改变,如下图所示(绿线所示):
参考代码如下:
int findLength(vector<int>& A, vector<int>& B) {
int m = A.size();
int n = B.size();
if (!m || !n) {
return 0;
}
vector<int> dp(n+1,0);
int res = 0;
for (int i = m-1; i >=0; i--) {
for (int j = 0; j < n; j++) {
dp[j] = (A[i] == B[j]) ? dp[j + 1] + 1 : 0;
res = max(res, dp[j]);
}
}
return res;
}