Valid Square
Compute all 6 pairwise squared distances — a square has exactly 4 equal smaller and 2 equal larger, with the diagonal = side * sqrt(2).
4 min read
geometry math
Problem#
Given 4 points, return true iff they form a square (any orientation, non-degenerate).
Examples#
(0,0), (1,1), (1,0), (0,1)→true.(0,0), (1,1), (1,0), (0,12)→false.
Constraints#
- Integer coordinates.
Approach#
Compute all 6 pairwise squared distances. A square has 4 equal “side” distances and 2 equal “diagonal” distances, with diagonal² = 2 * side². Also reject degenerate cases (zero side).
Solution#
class Solution {public: bool validSquare(vector<int>& p1, vector<int>& p2, vector<int>& p3, vector<int>& p4) { auto d2 = [](vector<int>& a, vector<int>& b) { long long dx = a[0] - b[0], dy = a[1] - b[1]; return dx * dx + dy * dy; }; vector<long long> ds = {d2(p1,p2), d2(p1,p3), d2(p1,p4), d2(p2,p3), d2(p2,p4), d2(p3,p4)}; sort(ds.begin(), ds.end()); if (ds[0] == 0) return false; return ds[0] == ds[1] && ds[1] == ds[2] && ds[2] == ds[3] && ds[4] == ds[5] && ds[4] == 2 * ds[0]; }};import "sort"
func validSquare(p1 []int, p2 []int, p3 []int, p4 []int) bool { d2 := func(a, b []int) int64 { dx := int64(a[0] - b[0]) dy := int64(a[1] - b[1]) return dx*dx + dy*dy } ds := []int64{d2(p1, p2), d2(p1, p3), d2(p1, p4), d2(p2, p3), d2(p2, p4), d2(p3, p4)} sort.Slice(ds, func(i, j int) bool { return ds[i] < ds[j] }) if ds[0] == 0 { return false } return ds[0] == ds[1] && ds[1] == ds[2] && ds[2] == ds[3] && ds[4] == ds[5] && ds[4] == 2*ds[0]}from typing import List
class Solution: def validSquare(self, p1: List[int], p2: List[int], p3: List[int], p4: List[int]) -> bool: def d2(a: List[int], b: List[int]) -> int: dx, dy = a[0] - b[0], a[1] - b[1] return dx * dx + dy * dy
ds = sorted([d2(p1, p2), d2(p1, p3), d2(p1, p4), d2(p2, p3), d2(p2, p4), d2(p3, p4)]) if ds[0] == 0: return False return (ds[0] == ds[1] == ds[2] == ds[3] and ds[4] == ds[5] and ds[4] == 2 * ds[0])function validSquare(p1, p2, p3, p4) { const d2 = (a, b) => { const dx = a[0] - b[0], dy = a[1] - b[1]; return dx * dx + dy * dy; }; const ds = [d2(p1, p2), d2(p1, p3), d2(p1, p4), d2(p2, p3), d2(p2, p4), d2(p3, p4)]; ds.sort((a, b) => a - b); if (ds[0] === 0) return false; return ds[0] === ds[1] && ds[1] === ds[2] && ds[2] === ds[3] && ds[4] === ds[5] && ds[4] === 2 * ds[0];}class Solution { public boolean validSquare(int[] p1, int[] p2, int[] p3, int[] p4) { long[] ds = { d2(p1, p2), d2(p1, p3), d2(p1, p4), d2(p2, p3), d2(p2, p4), d2(p3, p4) }; Arrays.sort(ds); if (ds[0] == 0) return false; return ds[0] == ds[1] && ds[1] == ds[2] && ds[2] == ds[3] && ds[4] == ds[5] && ds[4] == 2 * ds[0]; }
private long d2(int[] a, int[] b) { long dx = a[0] - b[0], dy = a[1] - b[1]; return dx * dx + dy * dy; }}function validSquare(p1: number[], p2: number[], p3: number[], p4: number[]): boolean { const d2 = (a: number[], b: number[]): number => { const dx = a[0] - b[0], dy = a[1] - b[1]; return dx * dx + dy * dy; }; const ds: number[] = [d2(p1, p2), d2(p1, p3), d2(p1, p4), d2(p2, p3), d2(p2, p4), d2(p3, p4)]; ds.sort((a, b) => a - b); if (ds[0] === 0) return false; return ds[0] === ds[1] && ds[1] === ds[2] && ds[2] === ds[3] && ds[4] === ds[5] && ds[4] === 2 * ds[0];}Editorial#
Using squared distances avoids floats. Sorting the 6 distances groups the 4 sides at the bottom and 2 diagonals at the top. The diagonal = 2 * side invariant rules out non-square rhombi/rectangles.
Complexity#
- Time:
O(1). - Space:
O(1).
Concept revision#
Related#