检测正方形
难度:
标签:
题目描述
给你一个在 X-Y 平面上的点构成的数据流。设计一个满足下述要求的算法:
- 添加 一个在数据流中的新点到某个数据结构中。可以添加 重复 的点,并会视作不同的点进行处理。
- 给你一个查询点,请你从数据结构中选出三个点,使这三个点和查询点一同构成一个 面积为正 的 轴对齐正方形 ,统计 满足该要求的方案数目。
轴对齐正方形 是一个正方形,除四条边长度相同外,还满足每条边都与 x-轴 或 y-轴 平行或垂直。
实现 DetectSquares
类:
DetectSquares()
使用空数据结构初始化对象void add(int[] point)
向数据结构添加一个新的点point = [x, y]
int count(int[] point)
统计按上述方式与点point = [x, y]
共同构造 轴对齐正方形 的方案数。
示例:

输入: ["DetectSquares", "add", "add", "add", "count", "count", "add", "count"] [[], [[3, 10]], [[11, 2]], [[3, 2]], [[11, 10]], [[14, 8]], [[11, 2]], [[11, 10]]] 输出: [null, null, null, null, 1, 0, null, 2] 解释: DetectSquares detectSquares = new DetectSquares(); detectSquares.add([3, 10]); detectSquares.add([11, 2]); detectSquares.add([3, 2]); detectSquares.count([11, 10]); // 返回 1 。你可以选择: // - 第一个,第二个,和第三个点 detectSquares.count([14, 8]); // 返回 0 。查询点无法与数据结构中的这些点构成正方形。 detectSquares.add([11, 2]); // 允许添加重复的点。 detectSquares.count([11, 10]); // 返回 2 。你可以选择: // - 第一个,第二个,和第三个点 // - 第一个,第三个,和第四个点
提示:
point.length == 2
0 <= x, y <= 1000
- 调用
add
和count
的 总次数 最多为5000
代码结果
运行时间: 90 ms, 内存: 17.8 MB
// 思路:使用Java Stream流式处理来实现相同的逻辑,通过Map来记录每个点的数量,并利用流来实现add和count方法。
import java.util.*;
import java.util.stream.*;
public class DetectSquares {
private Map<Integer, Map<Integer, Integer>> pointCount;
public DetectSquares() {
pointCount = new HashMap<>();
}
public void add(int[] point) {
int x = point[0], y = point[1];
pointCount.putIfAbsent(x, new HashMap<>());
pointCount.get(x).put(y, pointCount.get(x).getOrDefault(y, 0) + 1);
}
public int count(int[] point) {
int x1 = point[0], y1 = point[1];
return pointCount.getOrDefault(x1, Collections.emptyMap()).entrySet().stream()
.filter(e -> e.getKey() != y1)
.flatMapToInt(e -> {
int y2 = e.getKey();
int sideLength = Math.abs(y1 - y2);
int count1 = pointCount.getOrDefault(x1 + sideLength, Collections.emptyMap()).getOrDefault(y1, 0) *
pointCount.getOrDefault(x1 + sideLength, Collections.emptyMap()).getOrDefault(y2, 0);
int count2 = pointCount.getOrDefault(x1 - sideLength, Collections.emptyMap()).getOrDefault(y1, 0) *
pointCount.getOrDefault(x1 - sideLength, Collections.emptyMap()).getOrDefault(y2, 0);
return IntStream.of(count1 * e.getValue(), count2 * e.getValue());
})
.sum();
}
}
解释
方法:
本题解通过使用一个嵌套的字典结构来存储点的坐标和频率。外层字典的键是点的x坐标,而内层字典的键是y坐标,内层字典的值则是该点的出现频率。添加点时,只需简单增加该点的计数。在计数函数中,遍历与查询点x坐标相同的所有点,计算与查询点y坐标的距离(即边长),然后检查是否存在与查询点形成正方形的其他三个点。这种方法通过直接访问字典的键来验证点的存在性,避免了遍历整个数据结构的需要。
时间复杂度:
O(n) per query, where n is the number of points with the same x-coordinate as the query point
空间复杂度:
O(N) where N is the number of unique points in the data structure
代码细节讲解
🦆
在函数`count`中,你是如何确定遍历哪些点的?为什么只遍历与查询点x坐标相同的点?
▷🦆
在考虑正方形的两种可能的位置时,你如何保证这两种位置在平面上的实际存在性,特别是在边界条件如坐标为0或1000时?
▷🦆
你的解决方案在检测点的存在性时直接访问字典,这种方法在哪些情况下可能会引发错误或效率问题?
▷