Leetcode 2250. Count Number of Rectangles Containing Each Point
Woodyiiiiiii opened this issue · comments
一、 思路
这道题如果简单地使用两次遍历,O(n^2)的时间复杂度,会超时。从题目条件1 <= rectangles.length, points.length <= 5 * 10^4可以看出端倪,数据最大可以达到亿级别。
所以需要优化成O(nlgn)之类的复杂度,这就要使用到二分法或者分治法了。我们从题目条件发现x的范围很大,所以可以对x进行排序后二分,找到大于point的y坐标的矩阵边角,对于y我们可以排序聚合。
以下是上述做法:
class Solution {
public int[] countRectangles(int[][] rectangles, int[][] points) {
int[] res = new int[points.length];
int max = Integer.MIN_VALUE;
TreeMap<Integer, List<Integer>> map = new TreeMap<>();
for (int[] rectangle : rectangles) {
if (!map.containsKey(rectangle[1])) {
map.put(rectangle[1], new ArrayList<>());
}
List<Integer> list = map.get(rectangle[1]);
list.add(rectangle[0]);
max = Math.max(max, rectangle[1]);
}
for (int key : map.keySet()) {
List<Integer> list = map.get(key);
list.sort(Comparator.comparingInt(a -> a));
}
for (int j = 0; j < points.length; ++j) {
int cnt = 0;
if (points[j][1] > max) {
continue;
}
for (int key : map.subMap(points[j][1], max + 1).keySet()) {
if (key < points[j][1]) {
continue;
}
List<Integer> list = map.get(key);
int size = list.size();
int l = 0, r = size - 1;
int flag = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (list.get(mid) < points[j][0]) {
l = mid + 1;
} else {
flag = mid;
r = mid - 1;
}
}
if (flag < 0) {
continue;
}
cnt += (size - flag);
}
res[j] = cnt;
}
return res;
}
}
第二个做法是对points和rectangles排序,然后计算每个rectangle内部节点的出现次数,最后遍历points,查出对应的出现次数。首先需要对两者共同排序,先对x坐标从小到大排序,接着按照rectangle -> point的顺序排序,这样能够保证每个point之前的rectangle包围的点的出现次数不会漏掉。这样就绕开了数据范围较大的横坐标,直接对y坐标进行计算。
class Solution {
public int[] countRectangles(int[][] rectangles, int[][] points) {
int n = rectangles.length, Q = points.length;
int[][] es = new int[n + Q][];
for (int i = 0; i < n; i++) {
es[i] = rectangles[i];
}
for (int i = 0; i < Q; i++) {
es[n + i] = new int[]{points[i][0], points[i][1], i};
}
Arrays.sort(es, (x, y) -> {
if (x[0] != y[0]) {
return -(x[0] - y[0]);
}
return x.length - y.length;
});
int[] ct = new int[101];
int[] ans = new int[Q];
for (int[] e : es) {
if (e.length == 2) {
for (int i = 0; i <= e[1]; i++) {
ct[i]++;
}
} else {
ans[e[2]] = ct[e[1]];
}
}
return ans;
}
}