算法-動態規劃/滑動窗口-最長重複子數組

算法-動態規劃/滑動窗口-最長重複子數組

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)
O(m * n)

2.4 空間複雜度

O(m*n)

3 滑動窗口

3.1 思路

想想成兩把尺子,拿一把尺子A從尺子B上方滑過,每次就拿B尺子的首元素和上方位置的A元素開始往後比。

思路動圖詳見滑動窗口解法

3.2 代碼


3.3 時間複雜度

3.4 空間複雜度

O(m*n)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章