publicintfindLength(int[] A, int[] B){ int len = Math.min(A.length, B.length); int res_len = len; while (res_len > 0) { for (int ai = 0; ai + res_len <= len; ai++) { for (int bi = 0; bi + res_len <= len; bi++) { // 判断固定长度的子数组是否相等 if (subArrayIsSame(A, B, ai, bi, res_len)) { return res_len; } } } // 如果不相等,最大长度减一 res_len--; } return res_len; }
publicbooleansubArrayIsSame(int[] A, int[] B, int ai, int bi, int len){ for (int i = 0; i < len; i++) { if (A[ai + i] != B[bi + i]) { returnfalse; } } returntrue; }
复杂度分析
时间复杂度:Ο(N³),因为要遍历A、B和公共子数组。
空间复杂度:Ο(1)。
滑动窗口
以题目为例,它们的最长重复子数组是 [3, 2, 1],在 A 与 B 中的开始位置不同。但如果我们知道了开始位置,我们就可以根据它们将 A 和 B 进行「对齐」,即:
1 2 3
A = [1, 2, 3, 2, 1] B = [3, 2, 1, 4, 7] ↑ ↑ ↑
此时,最长重复子数组在 A 和 B 中的开始位置相同,我们就可以对这两个数组进行一次遍历,得到子数组的长度。我们可以枚举 A 和 B 所有的对齐方式。对齐的方式有两类:第一类为 A 不变,B 的首元素与 A 中的某个元素对齐;第二类为 B 不变,A 的首元素与 B 中的某个元素对齐。对于每一种对齐方式,我们计算它们相对位置相同的重复子数组即可。
publicintfindLength(int[] A, int[] B){ int lenA = A.length; int lenB = B.length; int ret = 0; for (int i = 0; i < lenA; i++) { int len = Math.min(lenA - i, lenB); int maxLen = maxLength(A, B, i, 0, len); ret = Math.max(ret, maxLen); }
for (int i = 0; i < lenB; i++) { int len = Math.min(lenB - i, lenA); int maxLen = maxLength(A, B, 0, i, len); ret = Math.max(ret, maxLen); } return ret; }
// 对齐后计算最长公共子数组 publicintmaxLength(int[] A, int[] B, int indexA, int indexB, int len){ int ret = 0; int maxLen = 0; for (int i = 0; i < len; i++) { if (A[indexA + i] == B[indexB + i]) { maxLen++; } else { maxLen = 0; } ret = Math.max(ret, maxLen); } return ret; }