Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given n points in the plane that are all distinct, where points[i] = [xi, yi]. A boomerang is a tuple of points (i, j, k) such that the distance between i and j equals the distance between i and k (the order of the tuple matters).
Return the number of boomerangs.
Example 1:
Input: points = [[0,0],[1,0],[2,0]] Output: 2 Explanation: The two boomerangs are [[1,0],[0,0],[2,0]] and [[1,0],[2,0],[0,0]].
Example 2:
Input: points = [[1,1],[2,2],[3,3]] Output: 2
Example 3:
Input: points = [[1,1]] Output: 0
Constraints:
n == points.length1 <= n <= 500points[i].length == 2-104 <= xi, yi <= 104Problem summary: You are given n points in the plane that are all distinct, where points[i] = [xi, yi]. A boomerang is a tuple of points (i, j, k) such that the distance between i and j equals the distance between i and k (the order of the tuple matters). Return the number of boomerangs.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Math
[[0,0],[1,0],[2,0]]
[[1,1],[2,2],[3,3]]
[[1,1]]
line-reflection)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #447: Number of Boomerangs
class Solution {
public int numberOfBoomerangs(int[][] points) {
int ans = 0;
for (int[] p1 : points) {
Map<Integer, Integer> cnt = new HashMap<>();
for (int[] p2 : points) {
int d = (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
ans += cnt.getOrDefault(d, 0);
cnt.merge(d, 1, Integer::sum);
}
}
return ans << 1;
}
}
// Accepted solution for LeetCode #447: Number of Boomerangs
func numberOfBoomerangs(points [][]int) (ans int) {
for _, p1 := range points {
cnt := map[int]int{}
for _, p2 := range points {
d := (p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1])
ans += cnt[d]
cnt[d]++
}
}
ans <<= 1
return
}
# Accepted solution for LeetCode #447: Number of Boomerangs
class Solution:
def numberOfBoomerangs(self, points: List[List[int]]) -> int:
ans = 0
for p1 in points:
cnt = Counter()
for p2 in points:
d = dist(p1, p2)
ans += cnt[d]
cnt[d] += 1
return ans << 1
// Accepted solution for LeetCode #447: Number of Boomerangs
struct Solution;
use std::collections::HashMap;
impl Solution {
fn distance_square(a: &[i32], b: &[i32]) -> i32 {
(a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])
}
fn number_of_boomerangs(points: Vec<Vec<i32>>) -> i32 {
let n = points.len();
let mut hm: HashMap<i32, i32> = HashMap::new();
let mut sum = 0;
for i in 0..n {
for j in 0..n {
if i == j {
continue;
}
let a = &points[i];
let b = &points[j];
let distance_square = Self::distance_square(a, b);
let ea = hm.entry(distance_square).or_default();
*ea += 1;
}
for &value in hm.values() {
if value > 1 {
sum += value * (value - 1);
}
}
hm.clear();
}
sum
}
}
#[test]
fn test() {
let points: Vec<Vec<i32>> = vec_vec_i32![[0, 0], [1, 0], [2, 0]];
assert_eq!(Solution::number_of_boomerangs(points), 2);
}
// Accepted solution for LeetCode #447: Number of Boomerangs
function numberOfBoomerangs(points: number[][]): number {
let ans = 0;
for (const [x1, y1] of points) {
const cnt: Map<number, number> = new Map();
for (const [x2, y2] of points) {
const d = (x1 - x2) ** 2 + (y1 - y2) ** 2;
ans += cnt.get(d) || 0;
cnt.set(d, (cnt.get(d) || 0) + 1);
}
}
return ans << 1;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.