2250. 统计包含每个点的矩形数目

题目描述:
给你一个二维整数数组 rectangles ,其中 rectangles[i] = [li, hi] 表示第 i 个矩形长为 li 高为 hi 。给你一个二维整数数组 points ,其中 points[j] = [xj, yj] 是坐标为 (xj, yj) 的一个点。

第 i 个矩形的 左下角 在 (0, 0) 处,右上角 在 (li, hi) 。

请你返回一个整数数组 count ,长度为 points.length,其中 count[j]是 包含 第 j 个点的矩形数目。

如果 0 <= xj <= li 且 0 <= yj <= hi ,那么我们说第 i 个矩形包含第 j 个点。如果一个点刚好在矩形的 边上 ,这个点也被视为被矩形包含。

示例1:
在这里插入图片描述

输入:rectangles = [[1,2],[2,3],[2,5]], points = [[2,1],[1,4]] 输出:[2,1]
解释: 第一个矩形不包含任何点。 第二个矩形只包含一个点 (2, 1) 。 第三个矩形包含点 (2, 1) 和 (1, 4) 。 包含点(2, 1) 的矩形数目为 2 。 包含点 (1, 4) 的矩形数目为 1 。 所以,我们返回 [2, 1] 。

示例2:
在这里插入图片描述

输入:rectangles = [[1,1],[2,2],[3,3]], points = [[1,3],[1,1]] 输出:[1,3]
解释: 第一个矩形只包含点 (1, 1) 。 第二个矩形只包含点 (1, 1) 。 第三个矩形包含点 (1, 3) 和 (1, 1) 。
包含点 (1, 3) 的矩形数目为 1 。 包含点 (1, 1) 的矩形数目为 3 。 所以,我们返回 [1, 3] 。

提示:

  • 1 <= rectangles.length, points.length <= 5 * 104
  • rectangles[i].length == points[j].length == 2
  • 1 <= li, xj <= 10^9
  • 1 <= hi, yj <= 100
  • 所有 rectangles 互不相同 。
  • 所有 points 互不相同 。

题目思路:
1.我们可以发现,只要矩形框的x,y值都大于等于point的x,y值,这个矩形框就满足条件。所以我们最容易想到的是使用暴力求解。但是根据提示发现,暴力破解会超时。所以我们换一种思路。
2.从提示中看出,y的取值范围比较小,而x的取值范围较大。所以我们可以先确定y的值,然后使用二分查找去找x的值。这样就不会超时了。

实现代码如下:

public int[] countRectangles(int[][] rectangles, int[][] points) {
        int[] count = new int[points.length];

        Arrays.sort(rectangles, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[1] == o2[1]) return o1[0] - o2[0];
                return o1[1] - o2[1];
            }
        });
        //先将`y`的取值存放到一个线性表中
        //这里我是为了省去判重的步骤,直接使用treeset,后面再将值存入线性表
        Set<Integer> set = new TreeSet<>();

        //哈希表中存储具有y高度的,x的取值
        Map<Integer, List<Integer>> map = new HashMap<>();
        //循环按上面所说的要求存储
        for (int[] rect : rectangles) {
            int x = rect[0], y = rect[1];
            map.putIfAbsent(y, new ArrayList<>());

            set.add(y);
            map.get(y).add(x);
        }
        //set中的值入表
        List<Integer> height = new ArrayList<>(set);

        int p = 0;

        for (int[] point : points) {
            int x = point[0], y = point[1];
            int startIdx = 0, sum = 0;
            //对于pinots中的每一个点,我们都先从先前的线性表height中遍历取得大于等于y的最小值
            //这里最多循环100次,因此直接线性查找即可
            while (startIdx < height.size() && height.get(startIdx) < y) startIdx++;
            while (startIdx < height.size()) {
                //获得以y为高度的,所有x的取值的表
                int h = height.get(startIdx);
                List<Integer> list = map.get(h);
                //二分查找符合要求的x的下标
                int q = binarySearch(list, x);
                //sum加上符合要求的个数
                sum += list.size() - q;
                //继续向后遍历
                startIdx++;
            }
            count[p] = sum;
            p++;
        }
        return count;
    }

    //这里我们的二分查找,是要找到大于等于point[0]的最小值
    int binarySearch(List<Integer> list, int x) {
        //表中的最大值都小于x,则不可能符合要求,直接返回
        if (list.get(list.size() - 1) < x) return list.size();
        //确定区间
        int left = 0, right = list.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            //小于x,不符合要求,区间左移
            if (list.get(mid) < x) {
                left = mid + 1;
            } else right = mid; //否则右移
        }
        return left;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值