Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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;
        
    }
    
}