我们用二元组 (x, y) 表示对 A 的偏移量 delta,其中 x 表示向左(负数)或向右(正数),y 表示向上(负数)或向下(正数)。在枚举偏移量时,我们可以分别枚举 A 和 B 中的一个 1,此时 delta 即为 A 中的 1 到 B 中的 1 的偏移量。枚举偏移量的时间复杂度为 O(N^4)。随后,我们对于 A 中的每个位置,判断它经过偏移后在 B 中的位置是否为 1。这一步的时间复杂度为 O(N^2)。
classSolution { publicintlargestOverlap(int[][] A, int[][] B) { intN= A.length; List<Point> A2 = newArrayList(), B2 = newArrayList(); for (inti=0; i < N*N; ++i) { if (A[i/N][i%N] == 1) A2.add(newPoint(i/N, i%N)); if (B[i/N][i%N] == 1) B2.add(newPoint(i/N, i%N)); }
Set<Point> Bset = newHashSet(B2);
intans=0; Set<Point> seen = newHashSet(); for (Point a: A2) for (Point b: B2) { Pointdelta=newPoint(b.x - a.x, b.y - a.y); if (!seen.contains(delta)) { seen.add(delta); intcand=0; for (Point p: A2) if (Bset.contains(newPoint(p.x + delta.x, p.y + delta.y))) cand++; ans = Math.max(ans, cand); } }
return ans; } }
[sol1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution(object): deflargestOverlap(self, A, B): N = len(A) A2 = [complex(r, c) for r, row inenumerate(A) for c, v inenumerate(row) if v] B2 = [complex(r, c) for r, row inenumerate(B) for c, v inenumerate(row) if v] Bset = set(B2) seen = set() ans = 0 for a in A2: for b in B2: d = b-a if d notin seen: seen.add(d) ans = max(ans, sum(x+d in Bset for x in A2)) return ans
复杂度分析
时间复杂度:O(N^6),其中 N 是数组 A 和 B 的边长。
空间复杂度:O(N^2)。
方法二:直接对偏移量计数
我们反向思考方法一,就可以得到一种新的方法。我们分别枚举 A 和 B 中的一个 1,计算出偏移量 delta 并放入计数器中。对于每一个 delta,如果它在计数器中出现了 k 次,那么偏移量为 delta 时,A 和 B 重合的 1 的数目就为 k。
[sol2]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { publicintlargestOverlap(int[][] A, int[][] B) { intN= A.length; int[][] count = newint[2*N+1][2*N+1]; for (inti=0; i < N; ++i) for (intj=0; j < N; ++j) if (A[i][j] == 1) for (inti2=0; i2 < N; ++i2) for (intj2=0; j2 < N; ++j2) if (B[i2][j2] == 1) count[i-i2 +N][j-j2 +N] += 1;
intans=0; for (int[] row: count) for (int v: row) ans = Math.max(ans, v); return ans; } }
[sol2]
1 2 3 4 5 6 7 8 9 10 11 12
classSolution(object): deflargestOverlap(self, A, B): N = len(A) count = collections.Counter() for i, row inenumerate(A): for j, v inenumerate(row): if v: for i2, row2 inenumerate(B): for j2, v2 inenumerate(row2): if v2: count[i-i2, j-j2] += 1 returnmax(count.values() or [0])