Leetcode 718.最長の繰り返しサブアレイ(DP;スライディングウィンドウ)

2021年3月25日木曜日は天気が良い[過去を嘆いたり、現在を無駄にしたり、未来を恐れたりしないでください]


1.はじめに

718.最も長く繰り返されるサブアレイ
ここに画像の説明を挿入

2.解決策

2.1動的計画法

ここに画像の説明を挿入

class Solution {
    
    
public:
    int findLength(vector<int>& A, vector<int>& B) {
    
    
        int m = A.size(), n = B.size();
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        int res = 0;
        for(int i=0;i<m;++i){
    
    
            for(int j=0;j<n;++j){
    
    
                dp[i+1][j+1] = A[i]==B[j]?dp[i][j]+1:0;
                res = max(res,dp[i+1][j+1]);
            }
        }
        return res;
    }
};

ここに画像の説明を挿入

スペース最適化バージョン:

class Solution {
    
    
public:
    int findLength(vector<int>& A, vector<int>& B) {
    
    
        int m = A.size(), n = B.size();
        // 始终使数组B的长度最小
        if(m<n) return findLength(B,A);
        vector<int> dp(n+1);
        int res = 0;
        for(int i=0;i<m;++i){
    
    
            // 从后往前计算dp,避免数据被覆盖
            for(int j=n-1;j>=0;--j){
    
    
                if(A[i]==B[j]) dp[j+1] = dp[j] + 1;
                else dp[j+1] = 0;
                res = max(res,dp[j+1]);
            }
        }
        return res;
    }
};

2.2スライディングウィンドウ(独創的なアイデア)

正直に言うと、私はこの質問のために考える最初の事はスライディングウィンドウ方法であった(ソース:下図のようにアイデアは、まだ非常に簡単です。スライディングウィンドウ液)が、残念ながらコードがwritten--ない
ここに画像の説明を挿入
場合上記のプロセスに従って直接記述します。コードは少しトリッキーになるので、考え方を変えることを検討しましょう。

配列アラインメントには2つのタイプがあります。最初のタイプは変更されていないAであり、Bの最初の要素はAの要素とアラインメントされます。アラインメントごとに、同じ相対位置で繰り返されるサブ配列を計算できます。(要約すると、最初の要素を揃え、最初に前方に移動し、2回目に後方に移動します

スライディングウィンドウ方式もプルーニングできます。共通の長さlen以下のres場合は、事前に返すことができます。

class Solution {
    
    
public:
    int findLength(vector<int>& A, vector<int>& B) {
    
    
        const int lenA = A.size(), lenB = B.size();
        int res = 0;
        // A 不变,B 的首元素与 A 中的某个元素对齐
        for(int i=0;i<lenA;++i){
    
    
            int len = min(lenB, lenA-i);
            if(len<=res) continue; // 剪枝
            int maxLen = helper(A,B,i,0,len);
            res = max(res,maxLen);
        }
        // B 不变,A 的首元素与 B 中的某个元素对齐
        for(int i=0;i<lenB;++i){
    
    
            int len = min(lenA, lenB-i);
            if(len<=res) continue; // 剪枝
            int maxLen = helper(A,B,0,i,len);
            res = max(res,maxLen);
        }
        return res;
    }

	// 给出两数组的首元素索引和重合长度,计算重合部分的最长重复子数组
    int helper(vector<int>& A, vector<int>& B, int begA, int begB, int len){
    
    
        int maxLen = 0, cnt = 0;
        for(int i=0;i<len;++i){
    
    
            if(A[begA+i]==B[begB+i]) ++cnt;
            else cnt = 0;
            maxLen = max(cnt,maxLen);
        }
        return maxLen;
    }
};

ここに画像の説明を挿入


参照

https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/zui-chang-zhong-fu-zi-shu-zu-by-leetcode-solution/

https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/wu-li-jie-fa-by-stg-2/

おすすめ

転載: blog.csdn.net/m0_37433111/article/details/115208629