題目:leetcode718. 最長重複子數組/動態規劃
給兩個整數數組 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
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
基本思想1:動態規劃
- dp[i][j]:以 A[i - 1]結束的子數組 和 B[j - 1]結束的子數組的最長匹配的個數,因爲這裏是子數組每個元素要連續(區別:子序列,子序列不連續)
- 狀態:兩個數組中的每一個字符
- 選擇:是否包含當前元素
- 狀態轉移方程:當前兩個元素相等,dp[i][j] = 1 + dp[i - 1][j - 1];不相等:dp[i][j] = dp[i - 1][j - 1]
說明:如果是最長子序列,dp數組的含義和狀態轉移方程均不一樣
- dp[i][j]:A的前 i 個字符和B的前 j 個字符最長匹配的子序列
- 狀態轉移方程:
時間複雜度:O(N * M)
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
//動態規劃
vector<vector<int>> dp(A.size() + 1, vector<int>(B.size() + 1, 0));
int res = 0;
for(int i = 1; i <= A.size(); ++i){
for(int j = 1; j <= B.size(); ++j){
if(A[i - 1] == B[j - 1]){
dp[i][j] = dp[i - 1][j - 1] + 1;
}
res = max(res, dp[i][j]);
//cout << dp[i][j] << " ";
}
//cout << endl;
}
return res;
}
};
基本思想2:滑動窗口
該思想是基於:最長子數組在兩個數組中的位置不一定相同,於是可以採取根據兩數組的不同對齊方式取找最長子數組
下述代碼中分兩步進行:
- 首先是A不變,B的首元素依次和A中的某個元素對齊,求解最長的重複子數組,求解的過程中如果兩個字符相等,遞增變量;否則,將變量置爲0,在這個過程中要不斷更新結果數組
- 然後是B不變,A的首元素依次和B中的某個元素對齊。接下來的過程是一樣的
時間複雜度:O((N +M)* min(N,M))
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
//滑動窗口
int res = 0, cur, k;
for(int i = 0; i < A.size(); ++i){//以A爲基準,滑動B
cur = 0;
k = i;
for(int j = 0; j < B.size() && k < A.size(); ++j,++k){
if(A[k] == B[j])
++cur;
else
cur = 0;
res = max(res, cur);
}
}
for(int i = 0; i < B.size(); ++i){//以B爲基準,滑動A
cur = 0;
k = i;
for(int j = 0; j < A.size() && k < B.size(); ++j, ++k){
if(B[k] == A[j])
++cur;
else
cur = 0;
res = max(res, cur);
}
}
return res;
}
};
基本思想3:暴力
求數組A中從 i 開始和數組B中從 j 開始的最長重複子數組,時間複雜度爲O(n3)