最长重复子数组

LeetCode算法网站算法题

https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/

一.动态规划

上来就瞎搞动态规划!!!

class Solution
{
public:
    int findLength(vector<int>& A, vector<int>& B)
    {
        int a=A.size();
        int b=B.size();
        vector<vector<int>>dp(a+1,vector<int>(b+1,0));
        for(int i=1;i<=a;i++)
        {
            for(int j=1;j<=b;j++)
            {
                if(A[i-1]==B[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else 
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return dp[a][b];
    }
};

后来在这个测试用例垮掉了!!

想了一下,可能我把dp[i][j]理解为A组中前i个数据与B组中前j个数据的最长公共子串的长度有失偏颇,正确应当是以A组中第i个数据和B组中第j个数据为最长公共子串的最后一个公共数据的最长公共子串的长度,所以当A[i]与B[j]不相等的时候dp[i][j]应该被赋值为0,否则像我第一次写的代码那样可能计算出来的就是两个数组的最长公共子序列了!!

更正DP

class Solution
{
public:
    int findLength(vector<int>& A, vector<int>& B)
    {
        int a=A.size();
        int b=B.size();
        int ans=0;
        vector<vector<int>>dp(a+1,vector<int>(b+1,0));
        for(int i=1;i<=a;i++)
        {
            for(int j=1;j<=b;j++)
            {
                if(A[i-1]==B[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else 
                    dp[i][j]=0;
                ans=max(ans,dp[i][j]);
            }
        }
        return ans;
    }
};

二.滑动窗口

思路就是,先把A数组相对于B数组向前滑动,findMax函数就是查找此时A,B数组相交的两部分的最长公共子串,但是仅这样滑动一次,每次都是包含B数组的前边一部分,所以这样会与正确答案有差异,因此需要再次把B数组相对A数组向前滑动,这样就可以每次计算都包含B数组的后面那部分了!!!!所以两次滑动并同时更新就可以获得正确答案!!

class Solution
{
private:
    int findMax(vector<int>&A,vector<int>&B,int sa,int sb,int&len)
    {
        int i;
        int k=0;
        int res=INT_MIN;
        for(i=0;i<len;i++)
        {
            if(A[sa+i]==B[sb+i])
                k++;
            else
                k=0;
            res=max(res,k);
        }
        return res;
    }
public:
    int findLength(vector<int>& A, vector<int>& B)
    {
      int a=A.size();
      int b=B.size();
      int ans=INT_MIN;
      for(int i=0;i<a;i++)
      {
          int len=min(a-i,b);
          int maxlen=findMax(A,B,i,0,len);
          ans=max(ans,maxlen);
      }
      for(int i=0;i<b;i++)
      {
          int len=min(b-i,a);
          int maxlen=findMax(A,B,0,i,len);
          ans=max(ans,maxlen);
      }
      return ans;
    }
};

三.二分查找+哈希——无情的复制粘贴,我一看这么长,不如前面两个好想也不好操作就没怎么看,以后有时间了可以看看拓展一下思路!!

class Solution
{
public:
    const int mod = 1000000009;
    const int base = 113;

    // 使用快速幂计算 x^n % mod 的值
    long long qPow(long long x, long long n)
    {
        long long ret = 1;
        while (n)
        {
            if (n & 1)
            {
                ret = ret * x % mod;
            }
            x = x * x % mod;
            n >>= 1;
        }
        return ret;
    }

    bool check(vector<int>& A, vector<int>& B, int len)
    {
        long long hashA = 0;
        for (int i = 0; i < len; i++)
        {
            hashA = (hashA * base + A[i]) % mod;
        }
        unordered_set<long long> bucketA;
        bucketA.insert(hashA);
        long long mult = qPow(base, len - 1);
        for (int i = len; i < A.size(); i++)
        {
            hashA = ((hashA - A[i - len] * mult % mod + mod) % mod * base + A[i]) % mod;
            bucketA.insert(hashA);
        }
        long long hashB = 0;
        for (int i = 0; i < len; i++)
        {
            hashB = (hashB * base + B[i]) % mod;
        }
        if (bucketA.count(hashB))
        {
            return true;
        }
        for (int i = len; i < B.size(); i++)
        {
            hashB = ((hashB - B[i - len] * mult % mod + mod) % mod * base + B[i]) % mod;
            if (bucketA.count(hashB))
            {
                return true;
            }
        }
        return false;
    }

    int findLength(vector<int>& A, vector<int>& B)
    {
        int left = 1, right = min(A.size(), B.size()) + 1;
        while (left < right)
        {
            int mid = (left + right) >> 1;
            if (check(A, B, mid))
            {
                left = mid + 1;
            }
            else
            {
                right = mid;
            }
        }
        return left - 1;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值