算法-動態規劃/滑動窗口-最長重複子數組
1 概述
1.1 題目出處
https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/
1.2 題目描述
給兩個整數數組 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
2 動態規劃
2.1 思路
這個首先肯定想到的是循環,但是很難解決,不可能每個遍歷一個數組的每個數又拿去到另一個數組遍歷吧,這樣時間複雜度直奔O(N^3)去了。
所以想想,是不是可以是父問題和子問題,貌似靠譜,那就試試動態規劃了:
- 如果dp[i][j] 表示取A[i]結尾,B[j]結尾的子數組的最長重複子數組長度,則無法推到dp[i][j]和dp[i-1][j-1]的關係,因爲無法確定到底是不是以A[i]B[j]作爲最長重複子數組的一部分
- 所以我們簡單考慮,dp[i][j] 表示取A[i]結尾,B[j]結尾的子數組作爲最長重複子數組時的最長重複子數組長度,則 :
- 如果A[i] = B[j],則dp[i][j] = dp[i-1][j-1] + 1
- 否則 dp[i][j] = 0
- 同時,我們在遍歷過程中記錄dp[i][j]最大值作爲結果
所以,用動態規劃的時候最重要的就是想清楚到底dp[i]表示什麼才能方便找到與dp[i-1]的關係,如果一種想不通必須立刻轉換思路,否則會導致你陷進去,時間耗光了卻找不到答案!
2.2 代碼
class Solution {
public int findLength(int[] A, int[] B) {
int minL = A.length < B.length ? A.length : B.length;
// 如果dp[i][j] 表示取A[i]結尾,B[j]結尾的子數組的最長重複子數組長度,則無法推到dp[i][j]和dp[i-1][j-1]的關係
// 因爲無法確定到底是不是以A[i]B[j]作爲最長重複子數組的一部分
// 所以我們簡單考慮,dp[i][j] 表示取A[i]結尾,B[j]結尾的子數組作爲最長重複子數組時的最長重複子數組長度
// 則 如果A[i] = B[j],則dp[i][j] = dp[i-1][j-1] + 1
// 否則 dp[i][j] = 0
// 同時,我們在遍歷過程中記錄dp[i][j]最大值作爲結果
// 這裏要注意,因爲我們需要從A[0]和B[0]開始判斷,
// 但有需要找dp[i][j]和dp[i-1][j-1]的關係
// 所以我們將dp最大值設爲dp[A.length][B.length]
int[][] dp = new int[A.length + 1][B.length + 1];
int result = 0;
for(int i = 1; i <= A.length; i++){
for(int j = 1; j <= B.length; j++){
if(A[i - 1] == B[j - 1]){
dp[i][j] = dp[i-1][j-1] + 1;
result = Math.max(dp[i][j], result);
}
}
}
return result;
}
}
2.3 時間複雜度
O(m * n)
2.4 空間複雜度
O(m*n)
3 滑動窗口
3.1 思路
想想成兩把尺子,拿一把尺子A從尺子B上方滑過,每次就拿B尺子的首元素和上方位置的A元素開始往後比。
思路動圖詳見滑動窗口解法
3.2 代碼
3.3 時間複雜度
3.4 空間複雜度
O(m*n)