Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leetcode 2250. Count Number of Rectangles Containing Each Point #104

Open
Woodyiiiiiii opened this issue Apr 24, 2022 · 0 comments
Open

Comments

@Woodyiiiiiii
Copy link
Owner

Woodyiiiiiii commented Apr 24, 2022

一、 思路

这道题如果简单地使用两次遍历,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;
        
    }
    
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant