LC 1453. Maximum Number of Darts Inside of a Circular Dartboard
https://leetcode.com/problems/maximum-number-of-darts-inside-of-a-circular-dartboard/
从这题的数据规模来看
1 <= points.length <= 100 points[i].length == 2 -10^4 <= points[i][0], points[i][1] <= 10^4 1 <= r <= 5000
有几种可能解决的办法:
- 对圆心进行二分搜索,但是似乎没有二分的依据
- 枚举圆心可能的位置,这个是正解
一开始我胡乱猜测:圆心位置肯定是在这几个点上,不过很容易证明这是错误的。"points = [[-2,0],[2,0],[0,2],[0,-2]], r = 2"
如果只有一个点在圆上呢?但是一个点没有办法确定圆心,必须有两个点才能确定。可是接着我们可以很容易继续往下推,证明至少有两个点会在圆上。
因为如果所有点都不在圆上的话,那么我们可以移动圆先让一个点A在圆上,接着可以对圆绕这个点A转动,让第二个点B到圆上。
这样操作下来,覆盖的点不会有任何变化,此时圆心可以根据两点AB确定下来。这样得到的圆心有两个,不过如果我们根据(A, B)以及(B,A)分别计算的话,每个case我们只需要计算一个圆心即可。
按照上面这个思路,我们只需要枚举所有的点对,计算出圆心,然后判断这个圆心最多覆盖多少个,这样下来时间复杂度就是O(n^3).
从A,B两点计算出圆心可以这样计算:
- 计算A->B的向量dx, dy
- 计算AB的中点mx, my
- 计算A到中点mx, my的距离d, 所以圆心到中点的距离就是 rd=sqrt(R^2-d^2)
- 圆心到中点的向量,和(dx,dy)是正交的话,所以这个向量应该是(-dy, dx)
- 根据向量和距离可以计算出这个圆心的位置
class Solution: def numPoints(self, points: List[List[int]], r: int) -> int: def find_center(x1, y1, x2, y2, r): dx, dy = x2 - x1, y2 - y1 mx, my = (x1 + x2) / 2, (y1 + y2) / 2 d2 = (mx - x1) ** 2 + (my - y1) ** 2 rd = (r * r - d2) ** 0.5 dxy = (dx ** 2 + dy ** 2) ** 0.5 x3 = -dy * rd / dxy + mx y3 = dx * rd / dxy + my return x3, y3 ans = 1 n = len(points) for i in range(n): x1, y1 = points[i] for j in range(n): x2, y2 = points[j] if i == j: continue if (x2 - x1) ** 2 + (y2 - y1) ** 2 > 4 * r * r: continue x3, y3 = find_center(x1, y1, x2, y2, r) res = 0 for k in range(n): if k == i or k == j: res += 1 continue x4, y4 = points[k] if (x3 - x4) ** 2 + (y3 - y4) ** 2 <= r * r: res += 1 ans = max(ans, res) return ans