力扣刷题笔记 718. 最长重复子数组 C#

博客介绍了如何解决力扣题目718,即找到两个整数数组中最长的公共子数组的长度。文章讨论了动态规划和滑动窗口两种解法,包括解法思路、时间复杂度和空间复杂度分析,并提供了相应的C#代码实现。
摘要由CSDN通过智能技术生成

题目如下

给两个整数数组 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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

最初实现使用暴力解法,3次循环,预料之中,提交结果超时,以下贴出代码,不做赘述。

public class Solution {
    public int FindLength(int[] A, int[] B) 
    {
        int count = 0;
        for (int i = 0; i < A.Length; i++)
        {
            for (int j = 0; j < B.Length; j++)
            {
                int k = 0;
                while(i + k < A.Length && j + k < B.Length && A[i + k] == B[j + k])
                {
                    k++;
                }
                if (k > count)
                {
                    count = k;
                }
            }
        }
        return count;
    }
}

解题失败后看官方解题思路,一共提出三种解法:

  1. 动态规划
  2. 滑动窗口
  3. 二分查找 + 哈希

解法3没有看懂,也没有尝试编写代码,以下自我回顾前两种解法,诉述可能有误,如有发现还请评论指出。

1.动态规划

假设数组为 A ,B,若 A[i] == B[j],将 A[i] 以及 A[i] 之后的元素集合视作 A[i] 子数组,记作A[i'],B[j'] 同理。

则以 A[i] 和 B[j] 开始的对比结果即为,A[i'] 和 B[j'] 从 0 开始最长的相同元素长度。

以此理解,因为A[i] == B[j],所以对比结果即为A[i'] 和 B[j'] 从 1 开始最长的相同元素长度 + 1,即以 A[i+1] 和 B[j + 1] 开始的对比结果。

所有的对比结果集合长度应为 数组 A 长度 * 数组 B 长度,故取一个二维数组 record 记录所有对比结果。

综上,record[i][j] = record[i+1][j+1]。

由于需要先获得向后的对比结果,所以对两个数组逆序遍历。

解法时间复杂度为两层逆序遍历 O(M*N),空间复杂度为记录结果的二维数组 O(M*N),M、N分别表示两个数组长度。

以下为代码:

public class Solution {
    public int FindLength(int[] A, int[] B) 
    {
        int[,] temp = new int[A.Length,B.Length];
        int ans = 0;
        for(int i = A.Length - 1; i >= 0;i--)
        {
            for(int j = B.Length - 1;j >= 0;j--)
            {
                if (i == A.Length - 1 || j == B.Length - 1)
                {
                    temp[i,j] = A[i] == B[j]? 1 : 0;
                }
                else
                {
                    temp[i,j] = A[i] == B[j]? temp[i + 1,j + 1] + 1 :0;
                }
                ans = Math.Max(ans,temp[i,j]);
            }
        }
        return ans;
    }
}

2.滑动窗口

最长子数组的起始点位置在两个数组中未必一致,故对比过程需要逐个遍历不同的起始位置。

由此,我们可以将两个数组以不同的起始位置对齐后开始比较,如,数组 A 从下标 1 开始逐格数组 B 从 0 开始的元素。

遍历 A 的每个下标作为起始位置对齐 B 的下标 0,再同理遍历 B 的每个标,即可获得所有起始点的对齐结果。

在以上的每次遍历当中,逐个向后对比字符是否相等,通过计数器记录,如果不相等则对比当前结果,然后中断重新记录。

对两个数组遍历结束,得出结果。

解法时间复杂度为 A B 两个数组分别遍历(M+N),乘以内层遍历的下标最大保护min(N,M), O((M+N)*min(N,M))。由于并未使用辅助集合,空间复杂度为O(1)。

此处引用力扣该题官方题解所用配图。

fig1

以下为代码:

public class Solution {
    public int FindLength(int[] A, int[] B) 
    {
        int ans = 0;
        for (int i = 0;i < A.Length;i++)
        {
            int len = Math.Min(B.Length, A.Length - i);
            int k = CheckLength(A,B,i,0,len);
            ans = Math.Max(ans,k);
        }
        for (int i = 0;i < B.Length;i++)
        {
            int len = Math.Min(A.Length, B.Length - i);
            int k = CheckLength(A,B,0,i,len);
            ans = Math.Max(ans,k);
        }
        return ans;
    }

    private int CheckLength(int[] A, int[] B,int baseA,int baseB, int len)
    {
        int ans = 0;
        int k = 0;
        for (int i = 0; i < len; i++)
        {
            if (A[baseA + i] == B[baseB + i])
            {
                k++;
            }
            else
            {
                ans = Math.Max(ans, k);
                k = 0;
            }
        }
        ans = Math.Max(ans, k);
        return ans;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值