Welcome to Subscribe On Youtube

Formatted question description: https://leetcode.ca/all/1453.html

1453. Maximum Number of Darts Inside of a Circular Dartboard

Level

Hard

Description

You have a very large square wall and a circular dartboard placed on the wall. You have been challenged to throw darts into the board blindfolded. Darts thrown at the wall are represented as an array of points on a 2D plane.

Return the maximum number of points that are within or lie on any circular dartboard of radius r.

Example 1:

Image text

Input: points = [[-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:

Image text

Input: points = [[-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).

Example 3:

Input: points = [[-2,0],[2,0],[0,2],[0,-2]], r = 1

Output: 1

Example 4:

Input: points = [[1,2],[3,5],[1,-1],[2,3],[4,1],[1,3]], r = 2

Output: 4

Constraints:

  • 1 <= points.length <= 100
  • points[i].length == 2
  • -10^4 <= points[i][0], points[i][1] <= 10^4
  • 1 <= r <= 5000

Solution

For each point in points, use point as the center and r as the radius to draw a circle. Then for each pair of points in points, calculate the intersection points of the two circles. For each intersection point, draw a circle with radius r and count the number of points within or lie on the circle. During the process, store the maximum number of points within or lie on the circles. Finally, return the maximum number of points.

The precision needs to be considered. To determine whether the distance between two points is less than or equal to r, use r + 1e-5 instead since one of the points is represented in data type double.

  • 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 + 1e-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]));
        }
    }
    
  • // OJ: https://leetcode.com/problems/maximum-number-of-darts-inside-of-a-circular-dartboard/
    // Time: O(N^3)
    // Space: O(1)
    class Solution {
        inline double dist(const vector<double> &a, const vector<double> &b) {
            return sqrt(pow(a[0] - b[0], 2) + pow(a[1] - b[1], 2));
        }
        vector<double> getPoint(const vector<double> &a, const vector<double> &b, double p, double q) {
            double x = (a[1] - b[1] + b[0] * q - a[0] * p) / (q - p);
            double y = a[1] + p * (x - a[0]);
            return {x, y};
        }
        vector<vector<double>> getCenters(const vector<double> &a, const vector<double> &b, int r) {
            double d = dist(a, b);
            if (d > 2 * r) return {};
            if (d == 2 * r) return { { (a[0] + b[0]) / 2, (a[1] + b[1]) / 2 } };
            double theta = acos(d / 2 / r);
            double alpha = atan2(a[1] - b[1], a[0] - b[0]);
            double p = tan(alpha + theta), q = tan(alpha - theta);
            return { getPoint(a, b, p, q), getPoint(a, b, q, p) };
        }
    public:
        int numPoints(vector<vector<int>>& A, int r) {
            int N = A.size(), ans = 0;
            for (int i = 0; i < N; ++i) {
                for (int j = 0; j < N; ++j) {
                    for (auto &center : getCenters({(double)A[i][0], (double)A[i][1]}, {(double)A[j][0], (double)A[j][1]}, r)) {
                        int cnt = 0;
                        for (auto &p : A) {
                            cnt += dist(center, {(double)p[0], (double)p[1]}) <= r + 0.00001;
                        }
                        ans = max(ans, cnt);
                    }
                }
            }
            return ans;
        }
    };
    
  • class Solution:
        def numPoints(self, darts: list[list[int]], r: int) -> int:
            def countDarts(x, y):
                count = 0
                for x1, y1 in darts:
                    if dist((x, y), (x1, y1)) <= r + 1e-7:
                        count += 1
                return count
    
            def possibleCenters(x1, y1, x2, y2):
                dx, dy = x2 - x1, y2 - y1
                d = sqrt(dx * dx + dy * dy)
                if d > 2 * r:
                    return []
                mid_x, mid_y = (x1 + x2) / 2, (y1 + y2) / 2
                dist_to_center = sqrt(r * r - (d / 2) * (d / 2))
                offset_x = dist_to_center * dy / d
                offset_y = dist_to_center * -dx / d
                return [
                    (mid_x + offset_x, mid_y + offset_y),
                    (mid_x - offset_x, mid_y - offset_y),
                ]
    
            n = len(darts)
            max_darts = 1
    
            for i in range(n):
                for j in range(i + 1, n):
                    centers = possibleCenters(
                        darts[i][0], darts[i][1], darts[j][0], darts[j][1]
                    )
                    for center in centers:
                        max_darts = max(max_darts, countDarts(center[0], center[1]))
    
            return max_darts
    
    

All Problems

All Solutions