最长重复子数组

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
    评论
好的,我了解了您的要求。以下是用C语言解决最长重复子数组的算法的分析PPT和相关代码解释: PPT分析: 最长重复子数组是指在一个数组中,找到两个相同的子数组,这两个子数组不能重叠,且它们的长度最长。例如,对于数组[1,2,3,2,1],最长重复子数组是[1,2,3,2,1]。 解决这个问题的常见方法是使用动态规划。具体来说,可以使用一个二维数组dp[i][j]表示A数组中以i结尾和B数组中以j结尾的最长公共前缀的长度。然后,遍历A数组和B数组,更新这个二维数组,最终找到最长的公共前缀的长度即可。 代码解释: 以下是用C语言实现最长重复子数组的代码。具体实现方式如下: ```c #include <stdio.h> int max(int a, int b) { return a > b ? a : b; } int findLength(int* A, int ASize, int* B, int BSize){ int dp[ASize+1][BSize+1]; int res = 0; for(int i=0; i<=ASize; i++) { for(int j=0; j<=BSize; j++) { if(i == 0 || j == 0) { dp[i][j] = 0; } else { if(A[i-1] == B[j-1]) { dp[i][j] = dp[i-1][j-1] + 1; res = max(res, dp[i][j]); } else { dp[i][j] = 0; } } } } return res; } int main() { int A[] = {1,2,3,2,1}; int B[] = {3,2,1,4,7}; int ASize = sizeof(A) / sizeof(A[0]); int BSize = sizeof(B) / sizeof(B[0]); printf("%d\n", findLength(A, ASize, B, BSize)); return 0; } ``` 在这个实现中,我们定义了一个max函数,用于比较两个数的大小。然后,我们定义了一个二维数组dp,用于记录A数组和B数组中的最长公共前缀长度。初始化时,我们将dp[i][j]设为0。然后,我们遍历A数组和B数组,如果A[i-1]等于B[j-1],则dp[i][j]等于dp[i-1][j-1]加上1,否则dp[i][j]等于0。在更新dp[i][j]的同时,我们还记录了当前的最长公共前缀长度res。最后,我们返回res即可。 希望这份分析PPT和代码解释对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值