Given two integer arrays A and B, return the maximum length of an subarray that appears in both arrays.

Example 1:

Input:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
Output: 3
Explanation:
The repeated subarray with maximum length is [3, 2, 1].

Note:

    1. 1 <= len(A), len(B) <= 1000
    2. 0 <= A[i], B[i] < 100

这道题给了我们两个数组A和B,让返回连个数组的最长重复子数组。那么如果将数组换成字符串,实际这道题就是求 Longest Common Substring 的问题了,而貌似 LeetCode 上并没有这种明显的要求最长相同子串的题,注意需要跟最长子序列 Longest Common Subsequence 区分开,关于最长子序列会在 follow up 中讨论。好,先来看这道题,既然是子数组,那么重复的地方一定是连续的,而且起点可能会是在数组中的任意地方,这样的话,最暴力的方法就是遍历A中的每个位置,把每个位置都当作是起点进行和B从开头比较,每次A和B都同时前进一个,假如相等,则计数器会累加1,不相等的话,计数器会重置为0,每次用计数器 cnt 的长度来更新结果 res。然后用同样的方法对B也处理一遍,把每个位置都当作是起点进行和A从开头比较,每次A和B都同时前进一个,这样最终下来,就可以求出最长重复子数组的长度,令人惊喜的是,这种暴力搜索解法的击败率相当的高,参见代码如下:

解法一:

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

我们还可以使用二分法+哈希表来做,别问博主怎么知道(看了题目标签,然后去论坛上找对应的解法即可,哈哈~)。虽然解法看起来很炫,但不太简洁,不是博主的 style,但还是收录进来吧。这里使用二分搜索法来找什么呢?其实是来直接查找最长重叠子数组的长度的,因为这个长度是有范围限制的,在 [0, min(m, n)] 之间,其中m和n分别是数组A和B的长度。这样每次折半出一个 mid,然后验证有没有这么一个长度为 mid 的子数组在A和B中都存在。从数组中取子数组有些麻烦,可以将数组转为字符串,取子串就相对来说容易一些了。将数组A和B都先转化为字符串 strA 和 strB,但是这里很 tricky,转换的方式不能是直接将整型数字转为字符串,再连接起来,这样会出错,因为会导致一个整型数占据多位字符,所以这里是需要将每个整型数直接加入字符串,从而将该整型数当作 ASCII 码来处理,寻找对应的字符,使得转换后的 strA 和 strB 变成各种凌乱的怪异字符,不过不影响解题。这里的二分应该属于博主之前的总结贴 LeetCode Binary Search Summary 二分搜索法小结 中的第四类,但是写法上却跟第三类的变形很像,因为博主平时的习惯是右边界设置为开区间,所以初始化为 min(m, n)+1,当然博主之前就说过二分搜索的写有各种各样的,像这个帖子中写法也是可以的。博主的这种写法实际上是在找第一个不大于目标值的数,这里的目标值就是那个 helper 子函数,也就是验证函数。如何实现这个验证函数呢,由于是要找长度为 len 的子串是否同时存在于 strA 和 strB 中,可以用一个 HashSet 保存 strA 中所有长度为 len 的子串,然后遍历 strB 中所有长度为 len 的子串,假如有任何一个在 HashSet 中存在,则直接返回 true,否则循环退出后,返回 false,参见代码如下:

解法二:

class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
string strA = stringify(A), strB = stringify(B);
int left = , right = min(A.size(), B.size()) + ;
while (left < right) {
int mid = (left + right) / ;
if (helper(strA, strB, mid)) left = mid + ;
else right = mid;
}
return right - ;
}
bool helper(string& strA, string& strB, int len) {
unordered_set<string> st;
for (int i = , j = len; j <= strA.size(); ++i, ++j) {
st.insert(strA.substr(i, j - i));
}
for (int i = , j = len; j <= strB.size(); ++i, ++j) {
if (st.count(strB.substr(i, j - i))) return true;
}
return false;
}
string stringify(vector<int>& nums) {
string res;
for (int num : nums) res += num;
return res;
}
};

对于这种求极值的问题,动态规划 Dynamic Programming 一直都是一个很好的选择,这里使用一个二维的 DP 数组,其中 dp[i][j] 表示数组A的前i个数字和数组B的前j个数字的最长子数组的长度,如果 dp[i][j] 不为0,则A中第i个数组和B中第j个数字必须相等,比对于这两个数组 [1,2,2] 和 [3,1,2],dp 数组为:

  3 1 2
0 0
0 0
0 0

注意观察,dp 值不为0的地方,都是当 A[i] == B[j] 的地方,而且还要加上左上方的 dp 值,即 dp[i-1][j-1],所以当前的 dp[i][j] 就等于 dp[i-1][j-1] + 1,而一旦 A[i] != B[j] 时,直接赋值为0,不用多想,因为子数组是要连续的,一旦不匹配了,就不能再增加长度了。每次算出一个 dp 值,都要用来更新结果 res,这样就能得到最长相同子数组的长度了,参见代码如下:

解法三:

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

Follow up:在开始时,博主提到了要跟最长相同子序列 Longest Common Subsequence 区分开来,虽然 LeetCode 没有直接求最大相同子序列的题,但有几道题利用到了求该问题的思想,比如 Delete Operation for Two Strings 和 Minimum ASCII Delete Sum for Two Strings 等,详细讨论请参见评论区一楼 :)

Github 同步地址:

https://github.com/grandyang/leetcode/issues/718

类似题目:

Minimum Size Subarray Sum

参考资料:

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

https://leetcode.com/problems/maximum-length-of-repeated-subarray/discuss/109068/JavaC%2B%2B-Clean-Code-8-lines

https://leetcode.com/problems/maximum-length-of-repeated-subarray/discuss/109039/Concise-Java-DP%3A-Same-idea-of-Longest-Common-Substring

https://leetcode.com/problems/maximum-length-of-repeated-subarray/discuss/109033/Solution-1%3A-DP-O(n2)-with-O(n)-space-Solution-2%3A-Stringify

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Maximum Length of Repeated Subarray 最长的重复子数组的更多相关文章

  1. [LeetCode] 718. Maximum Length of Repeated Subarray 最长的重复子数组

    Given two integer arrays A and B, return the maximum length of an subarray that appears in both arra ...

  2. [LeetCode]Maximum Length of Repeated Subarray

    Maximum Length of Repeated Subarray: Given two integer arrays A and B, return the maximum length of ...

  3. LeetCode 718. 最长重复子数组(Maximum Length of Repeated Subarray)

    718. 最长重复子数组 718. Maximum Length of Repeated Subarray 题目描述 给定一个含有 n 个正整数的数组和一个正整数 s,找出该数组中满足其和 ≥ s 的 ...

  4. 【LeetCode】718. Maximum Length of Repeated Subarray 解题报告(Python)

    [LeetCode]718. Maximum Length of Repeated Subarray 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxu ...

  5. 718. Maximum Length of Repeated Subarray

    Given two integer arrays A and B, return the maximum length of an subarray that appears in both arra ...

  6. LC 718. Maximum Length of Repeated Subarray

    Given two integer arrays A and B, return the maximum length of an subarray that appears in both arra ...

  7. Week 7 - 714. Best Time to Buy and Sell Stock with Transaction Fee & 718. Maximum Length of Repeated Subarray

    714. Best Time to Buy and Sell Stock with Transaction Fee - Medium Your are given an array of intege ...

  8. [Swift]LeetCode718. 最长重复子数组 | Maximum Length of Repeated Subarray

    Given two integer arrays A and B, return the maximum length of an subarray that appears in both arra ...

  9. [leetcode-718-Maximum Length of Repeated Subarray]

    Given two integer arrays A and B, return the maximum length of an subarray that appears in both arra ...

随机推荐

  1. Jmeter返回参数值写入文件《一》

    在用Jmeter做自动化测试的时候,某些特殊情况下我们需要将Jmeter的返回的某个特殊值写入的文件中,那么我们该如何做呢? 对于Jmeter这个工具来说,我们不难知道,它是一个java开源的可扩展的 ...

  2. ibatis.net 入门demo 实现基本增删改查

    1.项目架构体系  DAO(数据访问层)   Domain(实体层)  Text(表示层) 2.比较重要的是需要添加两个dll的引用,以及两个配置文件和一个XML文件 两个 IbatisNet.Com ...

  3. UGUI中显示粒子特效

    今天在UGUI上显示粒子特效的时候遇到的一些问题,Mark一下.原理:修改特效中每一个ParticleSystem的Layer为UI,并且把ParticleSystemRenderer.sorting ...

  4. 201621123040《Java程序设计》第12周学习总结

    1.本周学习总结 2.面向系统综合设计-图书馆管理系统或购物车 2.1简述如何使用流与文件改造你的系统.文件中数据的格式如何? 将书目信息写入文件,查阅图书馆书目信息时,实现文件的读取 2.2简述系统 ...

  5. JAVA使用和操作properties文件

    java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式,在properti ...

  6. Centos6.7下面配置vim及其插件

    Vim是在vi的基础上升级而来的,比vi更强大,提供代码补全,编译功能 [4]vim Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用 ...

  7. Web Api 返回图片流

    public class TestController : ApiController { public HttpResponseMessage GetImg() { //获取文件的绝对路径 stri ...

  8. SpringBoot14 SpringBoot整合mybatis

    1 版本说明 springboot:2.0 jdk:1.8 2 创建springBoot项目 创建项目时勾选必要web,MySQL,mybatis相关依赖 创建完成后再pom文件中添加自动部署.lom ...

  9. machine learning 之 logistic regression

    整理自Adrew Ng 的 machine learning课程week3 目录: 二分类问题 模型表示 decision boundary 损失函数 多分类问题 过拟合问题和正则化 什么是过拟合 如 ...

  10. emqtt 试用(八)ssl认证 - 代码验证

    参考链接:http://emqtt.com/clients#java http://docs.emqtt.cn/zh_CN/latest/config.html#mqtt-ssl-8883 一.单向认 ...