Problem
You are given a stream of points on the X-Y plane. Design an algorithm that:
- Adds new points from the stream into a data structure. Duplicate points are allowed and should be treated as different points.
- Given a query point, counts the number of ways to choose three points from the data structure such that the three points and the query point form an axis-aligned square with positive area.
An axis-aligned square is a square whose edges are all the same length and are either parallel or perpendicular to the x-axis and y-axis.
Implement the DetectSquares
class:
DetectSquares()
Initializes the object with an empty data structure.void add(int[] point)
Adds a new pointpoint = [x, y]
to the data structure.int count(int[] point)
Counts the number of ways to form axis-aligned squares with pointpoint = [x, y]
as described above.
Examples
Example 1:
|
|
Constraints
point.length == 2
0 <= x, y <= 1000
- At most
3000
calls in total will be made toadd
andcount
.
Solution
Method 1 – Diagonal Detection with Point Frequency Map
We can store all the points in hashmap, but also the counts as the duplicates are allowed.
Now the important part of coordinate geometry. How do we know if points are making square. We see the diagonal element.
Given p1, try all points p3 (p1 and p3 form diagonal)
- To compute
count(p1)
:- We try all points
p3
which together withp1
form the diagonal of non-empty square, it meansabs(p1.x-p3.x) == abs(p1.y-p3.y) && abs(p1.x-p3.x) > 0
- Since we have 2 points
p1
andp3
, we can form a square by computing the positions of 2 remain pointsp2
,p4
. p2 = (p1.x, p3.y)
p4 = (p3.x, p1.y)
- We try all points
Intuition
We store all points in a frequency map, allowing duplicates. The key geometric insight is that a square is defined by its diagonal. For a given query point, we try all possible points that could form a diagonal with it. If the absolute difference in x and y coordinates is equal and non-zero, these two points can be diagonally opposite in a square. The other two square corners can be computed directly.
For example, let the query point be $p_1 = (x_1, y_1)$ and another point $p_3 = (x_3, y_3)$ in the data structure. If $|x_1 - x_3| = |y_1 - y_3|$ and $x_1 \neq x_3$ and $y_1 \neq y_3$, then $p_1$ and $p_3$ can be diagonally opposite corners of a square. The other two corners are $p_1’ = (x_1, y_3)$ and $p_3’ = (x_3, y_1)$. The number of squares is the product of the counts of $p_1’$ and $p_3’$.
Approach
- Use a 2D array or map to count occurrences of each point.
- For add, increment the count for the given point.
- For count, iterate over all points that could form a diagonal with the query point (same distance in x and y, and not zero).
- For each diagonal, compute the other two corners and multiply their counts to get the number of squares.
- Sum the results for all possible diagonals.
Complexity
- ⏰ Time complexity:
O(1)
for add,O(T)
for count, whereT
is the number of points added. - 🧺 Space complexity:
O(T)
in Python,O(1000^2)
in C++/Java due to the grid size.
Code
|
|
|
|
|
|