|
| 1 | +# 最长重复子数组 |
| 2 | + |
| 3 | +<a name="273a27cc"></a> |
| 4 | +## 题目描述 |
| 5 | + |
| 6 | +<br />给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。<br /> |
| 7 | +<br />示例 1:<br /> |
| 8 | +<br />输入:<br /> |
| 9 | + |
| 10 | +```javascript |
| 11 | +A: [1,2,3,2,1] |
| 12 | +B: [3,2,1,4,7] |
| 13 | +输出: 3 |
| 14 | +解释: |
| 15 | +长度最长的公共子数组是 [3, 2, 1]。 |
| 16 | +``` |
| 17 | + |
| 18 | + |
| 19 | +<a name="d04d69d9"></a> |
| 20 | +## 解题方法 |
| 21 | + |
| 22 | + |
| 23 | +<a name="818f9b73"></a> |
| 24 | +### 方法一: 动态规划 |
| 25 | + |
| 26 | +<br />暴力解法:<br />枚举数组 A 中的起始位置 i 与数组 B 中的起始位置 j , 然后计算 A[i:] 与 B[i:]的最长公共子数组长度 k。最终答案即为所有的重复子数组的长度的最大值。<br /> |
| 27 | + |
| 28 | +> 这里借用 python 表示数组的方法, A[i:] 表示 数组 A 中索引 i 到数组末尾的范围对应的子数组。 |
| 29 | +
|
| 30 | + |
| 31 | + |
| 32 | +```javascript |
| 33 | +/** |
| 34 | + * @param {number[]} A |
| 35 | + * @param {number[]} B |
| 36 | + * @return {number} |
| 37 | + */ |
| 38 | +var findLength = function (A, B) { |
| 39 | + const m = A.length; |
| 40 | + const n = B.length; |
| 41 | + let res = 0; |
| 42 | + for (let i = 0; i < m; i++) { |
| 43 | + for (let j = 0; j < n; j++) { |
| 44 | + if (A[i] == B[j]) { |
| 45 | + // 遇到相同项 |
| 46 | + let subLen = 1; // 公共子序列长度至少为1 |
| 47 | + while ( |
| 48 | + A[i + subLen] == B[j + subLen] && // 它们下一项也相同 |
| 49 | + i + subLen < m && // 并且没有越界 |
| 50 | + j + subLen < n // 并且没有越界 |
| 51 | + ) { |
| 52 | + subLen++; // 公共子序列长度每次增加 1,考察新的一项 |
| 53 | + } |
| 54 | + res = Math.max(subLen, res); |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + return res; |
| 59 | +}; |
| 60 | +``` |
| 61 | + |
| 62 | +<br />暴力解法中,最快的情况就是 对于任意 i 与 j, A[i] 与 B[i] 比较了 min(i + 1, j + 1)次,这也是导致了该暴力解法时间复杂度过高的根本原因。<br /> |
| 63 | +<br />举个简单的例子:数组A 是[1, 2, 3], 数组B 是[1, 2, 4],那么在暴力解法中 A[2]与B[2]被比较了3次<br /> |
| 64 | + |
| 65 | +1. 起始位置 i = 0,j = 0的时候,分别比较 A[0]和 B[0], A[1]和B[1], A[2]和B[2] |
| 66 | +1. 起始位置 i = 1, j = 1 的时候,分别比较 A[1]和B[1], A[2]和B[2] |
| 67 | +1. 起始位置 i = 2, j = 2 的时候,分别比较 A[2]和B[2] |
| 68 | + |
| 69 | + |
| 70 | +<br />我们希望优化这过程,使得任意一对 A[i] 和 B[j]值被比较一次。我们很容易想到利用这一次的比较成果,如果 A[i] = B[j], 那么我们知道 A[i:]与 B[j:]的最长公共子数组长度为 A[i-1:]与 B[j-1:]的最长公共子数组长度 加 1,<br /> |
| 71 | + |
| 72 | +```javascript |
| 73 | +/** |
| 74 | + * @param {number[]} A |
| 75 | + * @param {number[]} B |
| 76 | + * @return {number} |
| 77 | + */ |
| 78 | +var findLength = function(A, B) { |
| 79 | + // 初始化一个二维数组,每一项都是 0 |
| 80 | + let m = A.length; |
| 81 | + let n = B.length; |
| 82 | + let dp = new Array(m + 1); |
| 83 | + for(let i = 0; i <= m; i++) { |
| 84 | + dp[i] = new Array(n + 1).fill(0); |
| 85 | + } |
| 86 | + let res = 0; |
| 87 | + for(let i = 1; i <= m; i++) { |
| 88 | + for(let j = 1; j <= n; j++) { |
| 89 | + if(A[i - 1] === B[j - 1]) { |
| 90 | + dp[i][j] = dp[i -1][j-1] + 1; |
| 91 | + } |
| 92 | + res = Math.max(dp[i][j], res) |
| 93 | + } |
| 94 | + } |
| 95 | + return res; |
| 96 | +}; |
| 97 | +``` |
| 98 | + |
| 99 | + |
| 100 | +<a name="9d1d8581"></a> |
| 101 | +## 方法二:滑动窗口 |
0 commit comments