列表

详情


1453. 圆形靶内的最大飞镖数量

墙壁上挂着一个圆形的飞镖靶。现在请你蒙着眼睛向靶上投掷飞镖。

投掷到墙上的飞镖用二维平面上的点坐标数组表示。飞镖靶的半径为 r

请返回能够落在 任意 半径为 r 的圆形靶内或靶上的最大飞镖数。

 

示例 1:

输入:points = [[-2,0],[2,0],[0,2],[0,-2]], r = 2
输出:4
解释:如果圆形的飞镖靶的圆心为 (0,0) ,半径为 2 ,所有的飞镖都落在靶上,此时落在靶上的飞镖数最大,值为 4 。

示例 2:

输入:points = [[-3,0],[3,0],[2,6],[5,4],[0,9],[7,8]], r = 5
输出:5
解释:如果圆形的飞镖靶的圆心为 (0,4) ,半径为 5 ,则除了 (7,8) 之外的飞镖都落在靶上,此时落在靶上的飞镖数最大,值为 5 。

示例 3:

输入:points = [[-2,0],[2,0],[0,2],[0,-2]], r = 1
输出:1

示例 4:

输入:points = [[1,2],[3,5],[1,-1],[2,3],[4,1],[1,3]], r = 2
输出:4

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int numPoints(vector<vector<int>>& darts, int r) { } };

java 解法, 执行用时: 140 ms, 内存消耗: 43.3 MB, 提交时间: 2023-09-18 14:58:28

class Solution {
    public double get_distance(double x1,double x2,double y1,double y2){
        double s=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
        return s;
    }
    public int numPoints(int[][] points, int r) {
        if(points.length<2)return points.length;
        int res=1;
        double d,x,y,center_x,center_y,h,x1,x2,y1,y2;
        for(int i=0;i<points.length;i++){
            for(int j=0;j<points.length;j++){
                if(i==j)continue;
                x1=points[i][0];
                y1=points[i][1];
                x2=points[j][0];
                y2=points[j][1];
                d=Math.sqrt(get_distance(x1,x2,y1,y2));
                if(d>2*r)continue;
                else{
                    x=(x1+x2)/2;
                    y=(y1+y2)/2;
                    if(x1==x2){
                       center_x=x;
                       center_y=y;
                    }
                    else{
                        h=Math.sqrt(r*r-(d/2)*(d/2));
                        center_x=h*(y2-y1)/d+x;
                        center_y=-h*(x2-x1)/d+y;
                    }   
                }
                System.out.println(center_x+" "+center_y);
                int count=0;
                for(int k=0;k<points.length;k++){
                    if(get_distance(points[k][0],center_x,points[k][1],center_y)-r*r<=0.00001){
                        count++;    
                    }   
                }
                res=Math.max(count,res);
            }
        }
        return res;
    }
}

python3 解法, 执行用时: 184 ms, 内存消耗: 17.4 MB, 提交时间: 2023-09-18 14:53:46

class Solution:
    def numPoints(self, points: List[List[int]], r: int) -> int:
        def helper(i, r, n):
            angles = []
            for j in range(n):
                if i != j and (l2 := sum([_ ** 2 for _ in vec[i][j]])) <= (2 * r) ** 2 + 1e-8:
                    C = math.acos(math.sqrt(l2) / (2 * r))
                    T = math.atan2(vec[i][j][1], vec[i][j][0])
                    _in = T - C
                    _out = T + C
                    angles.append([_in, True])
                    angles.append([_out, False])
            # 这里排序是重点, 考虑边界条件
            # 比如有 [0, False], [0, True]
            # 要让[0, True] 排到 [0, False]前面
            angles.sort(key=lambda x: [x[0], - x[1]])
            cnt = res = 1
            for item in angles:
                if item[1]:
                    cnt += 1
                else:
                    cnt -= 1
                if cnt > res:
                    res = cnt
            return res

        n = len(points)
        if n == 1:
            return 1
        # vec[i][j] = [Jx - Ix, J_y - Iy]
        # vec 存入两点之间的方向向量
        vec = [[[0, 0] for _ in range(n)] for __ in range(n)]
        for i in range(n - 1):
            for j in range(i + 1, n):
                JxIx = points[j][0] - points[i][0]
                JyIy = points[j][1] - points[i][1]
                vec[i][j] = [JxIx, JyIy]
                vec[j][i] = [-JxIx, -JyIy]
        ans = 0
        for i in range(n):
            ans = max(ans, helper(i, r, n))

        return ans

cpp 解法, 执行用时: 24 ms, 内存消耗: 14.8 MB, 提交时间: 2023-09-18 14:53:17

// Angular Sweep算法
const double PI = acos(-1);

class Solution {
public:
    int numPoints(vector<vector<int>>& points, int r) {
        if (points.empty()) return 0;
        int n = points.size();
        int ans = 1;
        // 遍历每一个点
        for (int i = 0; i < n; ++i) {
            vector<pair<double, double>> items;
            // 将能被覆盖的点的入角和出角加入 items
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                // 计算向量
                double xjxi = points[j][0] - points[i][0];
                double yjyi = points[j][1] - points[i][1];
                double dij = sqrt(xjxi * xjxi + yjyi * yjyi);
                if (dij > 2 * r + 1e-6) continue;
                // 计算角度
                double a = atan(yjyi / xjxi);
                if (xjxi < 0) a = (yjyi > 0) ? a + PI : a - PI; // 扩展到[-pi, pi]区域
                double b = acos(dij / (r * 2));
                items.push_back({a - b, -1});  
                items.push_back({a + b, 1});
            }
            sort(items.begin(), items.end());
            int cnt = 1;
            for (auto &p: items) {
                cnt -= p.second;
                if (cnt > ans) ans = cnt;
            }
        }
        return ans;
    }
};

cpp 解法, 执行用时: 24 ms, 内存消耗: 8.1 MB, 提交时间: 2023-09-18 14:51:29

struct point{
    double x,y;
    point(double i,double j):x(i),y(j){}
};

//算两点距离
double dist(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

//计算圆心
point f(point& a,point& b,int r){
    //算中点
    point mid((a.x+b.x)/2.0,(a.y+b.y)/2.0);
    //AB距离的一半
    double d=dist(a.x,a.y,mid.x,mid.y);
    //计算h
    double h=sqrt(r*r-d*d);
    //计算垂线
    point ba(b.x-a.x,b.y-a.y);
    point hd(-ba.y,ba.x);
    double len=sqrt(hd.x*hd.x+hd.y*hd.y);
    hd.x/=len,hd.y/=len;
    hd.x*=h,hd.y*=h;
    return point(hd.x+mid.x,hd.y+mid.y);
}

class Solution {
public:
    int numPoints(vector<vector<int>>& points, int r) {
        int n=points.size();
        //!!!!!r >= 1 所以初始化点必然是1,这样后续的i = j的计算可以省略
        int ans=1;
        for(int i=0;i<n;i++){
           //!!!!!从j + 1开始即可,对称的计算
            for(int j=i + 1;j<n;j++){
               
                    double d=dist(points[i][0],points[i][1],points[j][0],points[j][1]);
                    if(d/2>r) continue;

                    point a(points[i][0],points[i][1]),b(points[j][0],points[j][1]);
                    point res=f(a,b,r);
                    int cnt=0;
                    for(int k=0;k<n;k++){
                        double tmp=dist(res.x,res.y,points[k][0],points[k][1]);
                        if(tmp < r || fabs(tmp - r) < 1e-5) cnt++;
                    }
                    ans=max(cnt,ans);
                
            }
        }
        return ans;
    }
};

上一题