Leetcode 718. 最长重复子数组(DP;滑动窗口)

2021年03月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 滑动窗口(思路巧妙)

说实话,这道题我最先想到的就是滑动窗口法,思路还是很简单的,如下图所示(图源:滑动窗口解法),可惜代码没写出来- -
在这里插入图片描述
如果直接按照上面这个过程来写代码,会有点棘手,我们考虑转换一下思路。

数组对齐的方式有两类:第一类为 A 不变,B 的首元素与 A 中的某个元素对齐;第二类为 B 不变,A 的首元素与 B 中的某个元素对齐。 对于每一种对齐方式,我们计算它们相对位置相同的重复子数组即可。(总结下来就是:将首元素对齐,第一次往前移动,第二次往后移动

滑动窗口法还可以进行剪枝:如果公共长度 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