力扣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;
}
}