leetcode
leetcode 1951 ~ 2000
统计包含每个点的矩形数目

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

难度:

标签:

题目描述

给你一个二维整数数组 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 <= 109
  • 1 <= hi, yj <= 100
  • 所有 rectangles 互不相同 。
  • 所有 points 互不相同 。

代码结果

运行时间: 176 ms, 内存: 35.4 MB


/*
 * 思路: 
 * 使用Java Streams来简化和优化矩形检查的过程。对于每个点,
 * 使用Stream过滤出所有包含该点的矩形,最后统计数量。
 */
import java.util.Arrays;

public class Solution {
    public int[] countRectangles(int[][] rectangles, int[][] points) {
        return Arrays.stream(points)
                .mapToInt(point -> (int) Arrays.stream(rectangles)
                        .filter(rect -> point[0] <= rect[0] && point[1] <= rect[1])
                        .count())
                .toArray();
    }
}

解释

方法:

本题解采用二分查找的方法,首先对矩形数组按照高度从大到小排序,然后对点数组也按照高度从大到小排序。通过维护一个当前高度下所有矩形的宽度列表(按照宽度排序),对于每个点,找出在其高度要求下所有宽度足够的矩形,利用二分查找确定宽度能包含该点的矩形数量。在遍历点的过程中,随着点的高度的降低,逐渐增加满足条件的矩形宽度到列表中,并更新答案。

时间复杂度:

O((m+n) log(m+n))

空间复杂度:

O(m + n)

代码细节讲解

🦆
为什么在处理过程中需要将矩形和点的数组分别按照高度进行排序?
排序的目的是为了有效地处理每个点能被哪些矩形包含的问题。通过按高度降序排列矩形和点,我们可以确保在遍历点时,可以逐步将满足当前点高度条件的矩形宽度添加到考虑的列表中。这样的处理方式保证了每次添加的矩形都是对后续点来说可能有效的,从而避免了对每个点重新计算其上方的矩形,提高了效率。
🦆
在排序点数组后,为什么还需要使用一个额外的索引数组`points_indices`来存储排序后的索引?
在原始点数组按高度排序后,我们需要通过索引数组`points_indices`来保持点的原始顺序信息。这样做是因为最终输出的答案需要与输入点的顺序一致。通过使用索引数组,在处理完所有点之后,可以按照原始顺序将结果放置在正确的位置,确保输出的一致性。
🦆
在遍历点时,为什么要逐步将满足条件的矩形宽度添加到`rect_xs`列表中,而不是一开始就把所有矩形宽度添加进去?
这种逐步添加矩形的策略是为了优化算法效率。如果一开始就将所有矩形宽度添加到列表中,我们需要对每个点重新计算符合高度要求的矩形。而按点的高度顺序逐步加入矩形宽度,可以保证一旦矩形被加入列表,就无需再被移除,因为所有后续的点的高度都不会超过当前点。这样可以减少重复的计算和不必要的操作,优化整体的时间复杂度。
🦆
在代码中,二分查找使用了`bisect_left(rect_xs, x)`,这个函数的作用是什么,它如何帮助确定包含点的矩形数量?
`bisect_left`函数在一个已排序的列表中找到第一个不小于给定值x的元素的位置索引。在本题中,这个函数帮助我们快速定位列表`rect_xs`中第一个宽度不小于点x坐标的矩形的位置。由于`rect_xs`是升序的,从这个位置到列表末尾的所有矩形都是宽度大于等于x的,因此这个索引直接帮助我们计算出能包含该点的矩形数量。

相关问题