Talentd
FleetCode
Make and follow sheets.Sign in

Number of Boomerangs solution and explanation

MediumArrayHash TableMath5 min read58.0% acceptanceUpdated 9 Apr 2026
447. Number of Boomerangs | LEETCODE MEDIUMcode Explainer · 6:53 · 2K viewsWatch on YouTube
9 more videos on this problem
  1. 447. Number of Boomerangs | LEETCODE MEDIUMcode Explainer · 6:53 · 2K views
  2. 447. Number of Boomerangs (Leetcode Easy)Programming Live with Larry · 10:20 · 1K views
  3. LeetCode in Python 447. Number of Boomerangs - Michelle小梦想家Michelle小梦想家 · 12:19 · 1K views
  4. LeetCode 447. Number Of Boomerang, Data Structure & AlgorithmSourabh Saraswat · 39:57 · 534 views
  5. (C#)LeetCode 447 Number of Boomerangszongwu yang · 7:38 · 384 views
  6. Number of Boomerangs LeetCodeHustler Den · 4:33 · 342 views
  7. Number Of Boomerangs | Leetcode | Java | Solution | ExplanationCodingWithTricks · 10:39 · 313 views
  8. Number of Boomerangs | LeetCode 447 | HashMap + Geometry Logic Explained | Python DSANidhi Chouhan · 24:18 · 36 views
  9. No Sound Leetcode 447: Number of BoomerangsExtremeProgrammer · 1:18 · 25 views
  10. LeetCode 447: Number of BoomerangsAlitaCode · 30:18 · 8 views

The problem

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.length
  • 1 <= n <= 500
  • points[i].length == 2
  • -104 <= xi, yi <= 104
  • All the points are unique.

Approach overview

Problem Overview: You are given a list of 2D points. A boomerang is an ordered tuple of points (i, j, k) where the distance from i to j equals the distance from i to k. Order matters, so (i, j, k) and (i, k, j) count as different boomerangs. The goal is to count all such tuples across the set of points.

Approach 1: Distance Counting using HashMap (Time: O(n^2), Space: O(n))

Fix one point as the center i. Compute the squared Euclidean distance from i to every other point. Store frequencies of these distances in a HashMap. If a particular distance appears k times, it forms k * (k - 1) ordered pairs because each pair of points at that distance can be arranged in two directions. This approach avoids unnecessary square roots by using squared distance calculations and relies on constant-time hash lookups. The algorithm iterates through all points as centers, making it an efficient hash table based solution combined with simple array iteration.

Approach 2: Pre-computation and Lookup Table (Time: O(n^2), Space: O(n^2))

Instead of recomputing distances for each center point, precompute the pairwise squared distances between every pair of points and store them in a lookup table or matrix. After building this table, iterate over each center i and count how many points share the same distance value relative to i. Use the same combinational formula k * (k - 1) to count ordered pairs. This approach reduces repeated distance calculations but increases memory usage due to the stored matrix. The logic still relies on geometric distance properties from basic math operations.

Recommended for interviews: The hash map distance counting approach is what most interviewers expect. It demonstrates understanding of frequency counting, avoiding redundant work, and translating a geometric condition into a counting problem. Pre-computation can work but uses unnecessary memory. Showing the brute reasoning first (compare distances from a fixed center) and then optimizing with a hash map signals strong problem‑solving skills.

Approach 1: Approach 1: Distance Counting using HashMap

This approach involves treating each point as a base point and calculating the distance to all other points. A hashmap (or dictionary) is used to count occurrences of each distance. For any two points that share the same distance to the base point, we have two boomerangs.

from collections import defaultdict

class Solution:
    def numberOfBoomerangs(self, points: List[List[int]]) -> int:
        n = len(points)
        count = 0
        for i in range(n):
            dist_map = defaultdict(int)
            for j in range(n):
                if i == j:
                    continue
                dx = points[i][0] - points[j][0]
                dy = points[i][1] - points[j][1]
                dist = dx * dx + dy * dy
                dist_map[dist] += 1
            for value in dist_map.values():
                count += value * (value - 1)
        return count
import java.util.HashMap;
import java.util.Map;

public class Solution {
    public int numberOfBoomerangs(int[][] points) {
        int n = points.length;
        int count = 0;
        for (int i = 0; i < n; ++i) {
            Map<Integer, Integer> distMap = new HashMap<>();
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                int dx = points[i][0] - points[j][0];
                int dy = points[i][1] - points[j][1];
                int dist = dx * dx + dy * dy;
                distMap.put(dist, distMap.getOrDefault(dist, 0) + 1);
            }
            for (int value : distMap.values()) {
                count += value * (value - 1);
            }
        }
        return count;
    }
}
#include <vector>
#include <unordered_map>
using namespace std;

class Solution {
public:
    int numberOfBoomerangs(vector<vector<int>>& points) {
        int n = points.size();
        int count = 0;
        for (int i = 0; i < n; ++i) {
            unordered_map<int, int> distMap;
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                int dx = points[i][0] - points[j][0];
                int dy = points[i][1] - points[j][1];
                int dist = dx * dx + dy * dy;
                distMap[dist]++;
            }
            for (auto& entry : distMap) {
                count += entry.second * (entry.second - 1);
            }
        }
        return count;
    }
};
function numberOfBoomerangs(points) {
    let count = 0;
    const n = points.length;
    for (let i = 0; i < n; i++) {
        const distMap = new Map();
        for (let j = 0; j < n; j++) {
            if (i === j) continue;
            const dx = points[i][0] - points[j][0];
            const dy = points[i][1] - points[j][1];
            const dist = dx * dx + dy * dy;
            distMap.set(dist, (distMap.get(dist) || 0) + 1);
        }
        distMap.forEach(value => {
            count += value * (value - 1);
        });
    }
    return count;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 500

int numberOfBoomerangs(int** points, int pointsSize, int* pointsColSize) {
    int count = 0;
    int dist[SIZE] = {0};  // Assuming max dist

    for (int i = 0; i < pointsSize; ++i) {
        memset(dist, 0, sizeof(dist));
        for (int j = 0; j < pointsSize; ++j) {
            if (i == j) continue;
            int d = (points[i][0] - points[j][0]) * (points[i][0] - points[j][0]) + (points[i][1] - points[j][1]) * (points[i][1] - points[j][1]);
            dist[d]++;
        }
        for (int k = 0; k < SIZE; ++k) {
            if (dist[k] > 0) {
                count += dist[k] * (dist[k] - 1);
            }
        }
    }
    return count;
}
using System;
using System.Collections.Generic;

public class Solution {
    public int NumberOfBoomerangs(int[][] points) {
        int n = points.Length;
        int count = 0;
        for (int i = 0; i < n; ++i) {
            Dictionary<int, int> distMap = new Dictionary<int, int>();
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                int dx = points[i][0] - points[j][0];
                int dy = points[i][1] - points[j][1];
                int dist = dx * dx + dy * dy;
                if (!distMap.ContainsKey(dist)) {
                    distMap[dist] = 0;
                }
                distMap[dist]++;
            }
            foreach (var entry in distMap) {
                count += entry.Value * (entry.Value - 1);
            }
        }
        return count;
    }
}

This Python implementation uses `defaultdict` to automatically handle new distances and track their counts. It iterates through points, calculates distances, and uses the counts to calculate possible boomerangs.

Complexity

Time complexity is O(n^2), and space complexity is O(n) due to the defaultdict used for counting distances.

Try this approach in the editor

Approach 2: Approach 2: Pre-computation and Lookup Table

This approach involves using a lookup table to pre-compute square distance values. This can reduce some computational overhead during the distance calculation step by avoiding repetitive arithmetic operations.

from collections import defaultdict

class Solution:
    def numberOfBoomerangs(self, points: List[List[int]]) -> int:
        n = len(points)
        count = 0
        unique_distances = set()
        for i in range(n):
            dist_map = defaultdict(int)
            for j in range(n):
                if i == j:
                    continue
                dx = points[i][0] - points[j][0]
                dy = points[i][1] - points[j][1]
                dist = dx * dx + dy * dy
                dist_map[dist] += 1
                unique_distances.add(dist)
            for value in dist_map.values():
                count += value * (value - 1)
        return count
import java.util.HashMap;
import java.util.Map;

public class Solution {
    public int numberOfBoomerangs(int[][] points) {
        int n = points.length;
        int count = 0;
        Map<Integer, Integer> lookup = new HashMap<>();  // Lookup table
        for (int i = 0; i < n; ++i) {
            Map<Integer, Integer> distMap = new HashMap<>();
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                int dx = points[i][0] - points[j][0];
                int dy = points[i][1] - points[i][1];
                int dist = dx * dx + dy * dy;
                if (!lookup.containsKey(dist)) {
                    lookup.put(dist, dist);  // Just for demonstration, not needed actually
                }
                distMap.put(dist, distMap.getOrDefault(dist, 0) + 1);
            }
            for (int value : distMap.values()) {
                count += value * (value - 1);
            }
        }
        return count;
    }
}
#include <vector>
#include <unordered_map>
using namespace std;

class Solution {
public:
    int numberOfBoomerangs(vector<vector<int>>& points) {
        int n = points.size();
        int count = 0;
        vector<int> precomputed_sq_dist(n * 2, 0);
        for (int i = 0; i < n; ++i) {
            unordered_map<int, int> distMap;
            for (int j = 0; j < n; ++j) {
                if (i != j) {
                    int dx = points[i][0] - points[j][0];
                    int dy = points[i][1] - points[j][1];
                    int dist = precomputed_sq_dist[dx + dy];
                    distMap[dist]++;
                }
            }
            for (auto& entry : distMap) {
                count += entry.second * (entry.second - 1);
            }
        }
        return count;
    }
};
function numberOfBoomerangs(points) {
    let count = 0;
    const uniqueDistances = new Set();
    const n = points.length;
    for (let i = 0; i < n; i++) {
        const distMap = new Map();
        for (let j = 0; j < n; j++) {
            if (i === j) continue;
            const dx = points[i][0] - points[j][0];
            const dy = points[i][1] - points[j][1];
            const dist = dx * dx + dy * dy;
            uniqueDistances.add(dist);
            distMap.set(dist, (distMap.get(dist) || 0) + 1);
        }
        distMap.forEach(value => {
            count += value * (value - 1);
        });
    }
    return count;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_DIST 100000

int numberOfBoomerangs(int** points, int pointsSize, int* pointsColSize) {
    int count = 0;
    int *dist = (int*)malloc(MAX_DIST * sizeof(int));

    for (int i = 0; i < pointsSize; ++i) {
        memset(dist, 0, MAX_DIST * sizeof(int));
        for (int j = 0; j < pointsSize; ++j) {
            if (i == j) continue;
            int dx = points[i][0] - points[j][0];
            int dy = points[i][1] - points[j][1];
            int sqDist = dx * dx + dy * dy;
            dist[sqDist]++;
        }
        for (int k = 0; k < MAX_DIST; ++k) {
            if (dist[k] > 1) {
                count += dist[k] * (dist[k] - 1);
            }
        }
    }
    free(dist);
    return count;
}
using System;
using System.Collections.Generic;

public class Solution {
    public int NumberOfBoomerangs(int[][] points) {
        int n = points.Length;
        int count = 0;
        HashSet<int> uniqueDistances = new HashSet<int>();
        for (int i = 0; i < n; ++i) {
            Dictionary<int, int> distMap = new Dictionary<int, int>();
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                int dx = points[i][0] - points[j][0];
                int dy = points[i][1] - points[j][1];
                int dist = dx * dx + dy * dy;
                if (!uniqueDistances.Contains(dist)) {
                    uniqueDistances.Add(dist); 
                }
                if (!distMap.ContainsKey(dist)) {
                    distMap[dist] = 0;
                }
                distMap[dist]++;
            }
            foreach (var entry in distMap) {
                count += entry.Value * (entry.Value - 1);
            }
        }
        return count;
    }
}

This Python solution stores distances in a set to highlight pre-computation but doesn't actively use it beyond uniqueness count. It's primarily demonstrative.

Complexity

Time complexity is O(n^2), and it incurs extra space for storing set of all possible distances.

Try this approach in the editor

Approach 3: Enumeration + Counting

We can enumerate each point in points as the boomerang's point i, and then use a hash table cnt to record the number of times the distance from other points to i appears.

If there are x points with equal distance to i, then we can arbitrarily select two of them as the boomerang's j and k. The number of schemes is A_x^2 = x times (x - 1). Therefore, for each value x in the hash table, we calculate and accumulate A_x^2, which gives us the total number of boomerangs that meet the problem's requirements.

The time complexity is O(n^2), and the space complexity is O(n), where n is the length of the array points.

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;
}
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
}
Try this approach in the editor

Approach 4: Default Approach

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;
            cnt.set(d, (cnt.get(d) || 0) + 1);
        }
        for (const [_, x] of cnt) {
            ans += x * (x - 1);
        }
    }
    return ans;
}
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])
			cnt[d]++
		}
		for _, x := range cnt {
			ans += x * (x - 1)
		}
	}
	return
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Approach 1: Distance Counting using HashMap

Time complexity is O(n^2), and space complexity is O(n) due to the defaultdict used for counting distances.

Approach 2: Pre-computation and Lookup Table

Time complexity is O(n^2), and it incurs extra space for storing set of all possible distances.

Enumeration + Counting–
Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Distance Counting using HashMapO(n^2)O(n)General case and interview settings where memory efficiency and clarity matter
Pre-computation with Distance Lookup TableO(n^2)O(n^2)Useful if distances will be reused many times or precomputation is acceptable

Frequently asked questions

Is Number of Boomerangs easy or hard?

Number of Boomerangs is rated Medium because the brute-force idea is straightforward but recognizing the frequency counting trick with k * (k - 1) requires insight. Once that observation is made, the implementation becomes simple.

Number of Boomerangs Python/Java solution

Python typically uses a dictionary or collections.defaultdict to count distances, while Java uses HashMap<Integer, Integer>. Both implementations iterate through each point as a center and accumulate k * (k - 1) for matching distances.

How to solve Number of Boomerangs in O(n^2)?

Iterate through each point as the center i. Compute the squared distance from i to every other point and store counts in a hash map. If a distance appears k times, add k * (k - 1) to the answer since order matters between j and k.

What is the best approach for Number of Boomerangs?

The most efficient approach fixes each point as the center and counts distances to all other points using a hash map. For every distance that appears k times, it contributes k * (k - 1) ordered boomerangs. This runs in O(n^2) time and O(n) space and is the standard interview solution.

Is Number of Boomerangs asked at Google/Amazon/Meta?

Problems involving distance grouping, hash map counting, and geometric reasoning appear frequently in interviews at companies like Google, Amazon, and Meta. Number of Boomerangs tests the ability to transform a geometric condition into a counting problem using hashing.

What data structure is used in Number of Boomerangs?

A hash table (HashMap or dictionary) is the primary data structure. It stores the frequency of squared distances from a fixed center point to all other points, enabling constant-time updates and lookups while counting boomerangs.

What is the time complexity of Number of Boomerangs?

The optimal solution runs in O(n^2) time because for each point you compute distances to every other point. The hash map stores frequency counts of distances for that center. Space complexity is O(n) for the distance frequency map.

Comments

Now write it yourselfClose this page and solve Number of Boomerangs in the editor, without looking.
Practise Number of Boomerangs