1. Problem Summary
You are given four points in a 2D plane.
Each point is represented by a pair of integers:
[x, y]
Your task is to determine whether these four points form a square, regardless of their ordering.
To be considered a valid square:
- All four sides must have equal non-zero length
- The two diagonals must have equal length
- Points must be distinct
- Shape must not collapse into a line or a point
Example interpretation:
If the points are:
[0,0], [1,1], [1,0], [0,1]
These form a perfect square → return true.
2. Key Insights
Distance comparisons are sufficient
We do not need to compute angles or slopes.
All necessary properties come from squared distances.
Use squared distances to avoid floating point math
Distance squared formula:
d² = (x1 - x2)² + (y1 - y2)²
A valid square always has:
- exactly 4 equal smaller distances (sides)
- exactly 2 equal larger distances (diagonals)
Reject invalid configurations
- if any squared distance is zero → overlapping points → not a square
- if unique distance pattern does not match 4 + 2 grouping → not a square
Order of points does not matter
Therefore we compare all pairwise distances.
3. Approach
Compute all pairwise squared distances and analyze counts
Steps:
- Extract the four points
- Compute squared distance between every pair (6 total distances)
- Store distances in a list
- Sort the list
- Validate:
- first four distances equal (sides)
- last two distances equal (diagonals)
- side distance > 0
- diagonal distance > side distance
If all conditions satisfied → return true
Otherwise → return false
4. Time and Space Complexity
Time Complexity: O(1)
Fixed number of operations (6 distances)
Space Complexity: O(1)
Uses constant storage
5. Java Solution
class Solution {
private int distSq(int[] p1, int[] p2) {
int dx = p1[0] - p2[0];
int dy = p1[1] - p2[1];
return dx * dx + dy * dy;
}
public boolean validSquare(int[] p1, int[] p2, int[] p3, int[] p4) {
int[] distances = new int[6];
distances[0] = distSq(p1, p2);
distances[1] = distSq(p1, p3);
distances[2] = distSq(p1, p4);
distances[3] = distSq(p2, p3);
distances[4] = distSq(p2, p4);
distances[5] = distSq(p3, p4);
Arrays.sort(distances);
// Check that sides are positive and equal
if (distances[0] == 0) return false;
// First four should be sides, last two diagonals
boolean sidesEqual = distances[0] == distances[1] &&
distances[1] == distances[2] &&
distances[2] == distances[3];
boolean diagonalsEqual = distances[4] == distances[5];
boolean diagonalGreater = distances[4] > distances[0];
return sidesEqual && diagonalsEqual && diagonalGreater;
}
}
6. Dry Run Examples
Example 1
Input:
p1 = [0,0] p2 = [1,1] p3 = [1,0] p4 = [0,1]
Pairwise squared distances:
1,1,2,1,2,1
Sorted:
1,1,1,1,2,2
Checks:
- first four equal → yes
- non-zero → yes
- last two equal → yes
- diagonal > side → yes
Output:
true
Example 2
Input:
p1 = [0,0] p2 = [2,0] p3 = [3,1] p4 = [1,1]
Distances produce unequal sides pattern
Output:
false
Example 3
Input:
p1 = [1,1] p2 = [1,1] p3 = [2,2] p4 = [3,3]
Zero distances due to duplicate points
Output:
false
Example 4
Input:
p1 = [0,0] p2 = [2,0] p3 = [4,0] p4 = [6,0]
All collinear
Output:
false
7. Why This Solution Works
- Distances determine square properties uniquely
- Avoids orientation and floating-point issues
- Order-independent evaluation
- Properly rules out degenerate cases
- Applies strict geometric invariants
8. Common Mistakes
- Using actual Euclidean distance instead of squared → floating precision issues
- Assuming points arrive in order → incorrect
- Forgetting to check for duplicate points
- Misinterpreting rectangles as squares
- Checking slopes (unnecessary and error-prone)
