Maximum Number of Darts Inside of a Circular Dartboard
HardPrompt
Alice is throwing n darts on a very large wall. You are given an array darts where darts[i] = [xi, yi] is the position of the ith dart that Alice threw on the wall.
Bob knows the positions of the n darts on the wall. He wants to place a dartboard of radius r on the wall so that the maximum number of darts that Alice throws lie on the dartboard.
Given the integer r, return the maximum number of darts that can lie on the dartboard.
Example 1:
Input: darts = [[-2,0],[2,0],[0,2],[0,-2]], r = 2
Output: 4
Explanation: Circle dartboard with center in (0,0) and radius = 2 contain all points.Example 2:
Input: darts = [[-3,0],[3,0],[2,6],[5,4],[0,9],[7,8]], r = 5
Output: 5
Explanation: Circle dartboard with center in (0,4) and radius = 5 contain all points except the point (7,8).
Constraints:
1 <= darts.length <= 100darts[i].length == 2-104 <= xi, yi <= 104- All the
dartsare unique 1 <= r <= 5000
Approaches
2 approaches with complexity analysis and trade-offs.
The fundamental insight for this approach is that an optimal circle (one containing the maximum number of darts) of a fixed radius r will, in general, have at least two of the darts on its boundary. If an optimal circle had fewer than two darts on its boundary, it could be moved without losing any enclosed darts until its boundary touched at least two darts. This allows us to drastically reduce the search space for the circle's center. Instead of checking an infinite number of possible centers, we only need to consider circles that are defined by pairs of darts.
Algorithm
- Initialize
maxDartsto 1, as a single dart can always be enclosed. - Iterate through every possible pair of darts,
darts[i]anddarts[j]. - For each pair, calculate the distance
dbetween them. - If
d > 2 * r, no circle of radiusrcan contain both darts. Continue to the next pair. - If
d <= 2 * r, there are two circles of radiusrthat pass through bothdarts[i]anddarts[j]. We need to find their centers.- Calculate the midpoint
Mof the line segment connecting the two darts. - The distance from
Mto either center ish = sqrt(r^2 - (d/2)^2). - The centers lie on the perpendicular bisector of the segment, at distance
hfromM. Calculate the coordinates of these two centers,C1andC2.
- Calculate the midpoint
- For each center (
C1andC2):- Initialize a counter to 0.
- Iterate through all
ndarts and check if their distance from the current center is less than or equal tor(with a small tolerance for floating-point errors). - Increment the counter for each dart inside the circle.
- Update
maxDartswith the maximum count found so far. - After checking all pairs, return
maxDarts.
Walkthrough
This method iterates through all unique pairs of darts. For each pair, it calculates the centers of the two possible circles of radius r that have both darts on their circumference. Then, for each of these two potential circles, it counts how many of the total darts fall within it. The maximum count found across all tested circles is the answer.
Here is the algorithm:
- Initialize
maxDartsto 1, as a single dart can always be enclosed. - Iterate through every possible pair of darts,
darts[i]anddarts[j]. - For each pair, calculate the distance
dbetween them. - If
d > 2 * r, no circle of radiusrcan contain both darts. Continue to the next pair. - If
d <= 2 * r, there are two circles of radiusrthat pass through bothdarts[i]anddarts[j]. We need to find their centers.- Calculate the midpoint
Mof the line segment connecting the two darts. - The distance from
Mto either center ish = sqrt(r^2 - (d/2)^2). - The centers lie on the perpendicular bisector of the segment, at distance
hfromM. Calculate the coordinates of these two centers,C1andC2.
- Calculate the midpoint
- For each center (
C1andC2):- Initialize a counter to 0.
- Iterate through all
ndarts and check if their distance from the current center is less than or equal tor(with a small tolerance for floating-point errors). - Increment the counter for each dart inside the circle.
- Update
maxDartswith the maximum count found so far. - After checking all pairs, return
maxDarts.
class Solution { public int numPoints(int[][] darts, int r) { int n = darts.length; if (n <= 1) { return n; } int maxDarts = 1; double rDouble = (double) r; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { double x1 = darts[i][0], y1 = darts[i][1]; double x2 = darts[j][0], y2 = darts[j][1]; double distSq = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); if (distSq > 4 * rDouble * rDouble + 1e-9) { continue; } double mx = (x1 + x2) / 2.0; double my = (y1 + y2) / 2.0; double dist = Math.sqrt(distSq); double h = Math.sqrt(Math.max(0.0, rDouble * rDouble - distSq / 4.0)); double dx = x2 - x1; double dy = y2 - y1; double cx1 = mx + h * dy / dist; double cy1 = my - h * dx / dist; double cx2 = mx - h * dy / dist; double cy2 = my + h * dx / dist; int count1 = 0; for (int k = 0; k < n; k++) { double px = darts[k][0], py = darts[k][1]; if ((px - cx1) * (px - cx1) + (py - cy1) * (py - cy1) <= rDouble * rDouble + 1e-9) { count1++; } } maxDarts = Math.max(maxDarts, count1); int count2 = 0; for (int k = 0; k < n; k++) { double px = darts[k][0], py = darts[k][1]; if ((px - cx2) * (px - cx2) + (py - cy2) * (py - cy2) <= rDouble * rDouble + 1e-9) { count2++; } } maxDarts = Math.max(maxDarts, count2); } } return maxDarts; }}Complexity
Time
O(n^3). There are two nested loops to iterate through all `O(n^2)` pairs of darts. For each pair, we find two candidate centers. For each center, we loop through all `n` darts to count how many are inside the circle. This results in a total time complexity of `O(n^2 * n) = O(n^3)`.
Space
O(1) extra space, as we only need a few variables to store coordinates, distances, and counts.
Trade-offs
Pros
Relatively simple to understand and implement based on a clear geometric property.
Sufficiently efficient for the given constraints (
n <= 100).
Cons
Its
O(n^3)time complexity makes it less suitable for larger values ofn.Relies on floating-point arithmetic, which can introduce precision errors. A small epsilon value is needed for comparisons.
Solutions
Solution
class Solution {public int numPoints(int[][] points, int r) { int maxPoints = 1; int pointsCount = points.length; for (int i = 0; i < pointsCount; i++) { for (int j = i + 1; j < pointsCount; j++) { double[][] intersections = getIntersections(points[i], points[j], r); for (double[] intersection : intersections) { int pointsInCircle = 0; for (int[] point : points) { double distance = distance(intersection, point); if (distance <= r + 1 e - 5) pointsInCircle++; } maxPoints = Math.max(maxPoints, pointsInCircle); } } } return maxPoints; }public double[][] getIntersections(int[] point1, int[] point2, int radius) { int squaredDistance = squaredDistance(point1, point2); if (squaredDistance > radius * radius * 4) return new double[0][2]; else if (squaredDistance == radius * radius * 4) { double[] intersection = new double[2]; for (int i = 0; i < 2; i++) intersection[i] = (point1[i] + point2[i]) / 2.0; double[][] intersections = new double[1][2]; intersections[0] = intersection; return intersections; } else { double[] midPoint = new double[2]; for (int i = 0; i < 2; i++) midPoint[i] = (point1[i] + point2[i]) / 2.0; double remaining = Math.sqrt(radius * radius - squaredDistance / 4.0); int difference1 = point1[1] - point2[1]; int difference2 = point2[0] - point1[0]; double radian = Math.atan(1.0 * difference2 / difference1); double[] intersection0 = {midPoint[0] + remaining * Math.cos(radian), midPoint[1] + remaining * Math.sin(radian)}; double[] intersection1 = {midPoint[0] - remaining * Math.cos(radian), midPoint[1] - remaining * Math.sin(radian)}; double[][] intersections = new double[2][2]; intersections[0] = intersection0; intersections[1] = intersection1; return intersections; } }public int squaredDistance(int[] point1, int[] point2) { return (point2[0] - point1[0]) * (point2[0] - point1[0]) + (point2[1] - point1[1]) * (point2[1] - point1[1]); }public double distance(double[] point1, int[] point2) { return Math.sqrt((point2[0] - point1[0]) * (point2[0] - point1[0]) + (point2[1] - point1[1]) * (point2[1] - point1[1])); }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.