题目描述:
给你一个二维整数数组 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;
}