给两个整数数组 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; }