【算法题解析】统计圆内点的数量 —— LeetCode 1828 “统计圆内点的数目”
题目描述
给你一个二维平面上的点集 points
,其中每个点 points[i] = [x_i, y_i]
表示第 i
个点的坐标。注意,可能存在多个点坐标相同的情况。
同时给你一个查询列表 queries
,其中每个查询 queries[j] = [x_j, y_j, r_j]
表示一个圆,圆心为 (x_j, y_j)
,半径为 r_j
。
请你对每个查询圆统计:有多少点位于该圆内或圆的边界上。最后返回一个数组 answer
,其中 answer[j]
是第 j
个查询的答案。
解题分析
题目要求我们对于多个圆查询,统计这些圆内包含的点的个数。对每个查询圆,我们需要检查所有点,判断它们是否落在该圆内。
判断点 (x_i, y_i)
是否在以 (x_j, y_j)
为圆心、半径为 r_j
的圆内的条件是:
(xi−xj)2+(yi−yj)2≤rj2(x_i - x_j)^2 + (y_i - y_j)^2 \leq r_j^2(xi−xj)2+(yi−yj)2≤rj2
满足该条件的点计数即为答案。
解决方案
方法一:暴力枚举
对每一个查询圆,遍历所有点,判断点是否在圆内,统计数量。
- 步骤:
- 初始化一个结果数组
answer
。 - 对于每个查询圆
(x_j, y_j, r_j)
:- 计算半径平方
r_j^2
。 - 遍历所有点
(x_i, y_i)
:- 判断
(x_i - x_j)^2 + (y_i - y_j)^2
是否小于等于r_j^2
。 - 如果满足,计数器加一。
- 判断
- 将计数结果加入
answer
。
- 计算半径平方
- 返回
answer
。
- 初始化一个结果数组
- 代码示例(Python):
from typing import List
class Solution:
def countPoints(self, points: List[List[int]], queries: List[List[int]]) -> List[int]:
answer = []
for xj, yj, rj in queries:
count = 0
r_sq = rj * rj
for xi, yi in points:
dx = xi - xj
dy = yi - yj
if dx * dx + dy * dy <= r_sq:
count += 1
answer.append(count)
return answer
复杂度分析
- 时间复杂度:
由于对每个查询,我们都遍历一遍所有点,时间复杂度为 O(Q * N),其中 Q 是查询数量,N 是点的数量。 - 空间复杂度:
除了存储输入和输出,空间开销为常数 O(1)。
优化思路
当点和查询数量特别大时,暴力方法可能会超时。可采用空间数据结构进行优化,比如:
- 空间划分结构:四叉树 (Quadtree)、KD 树等,用于快速查询空间范围内的点。
- 离散化 + 预处理:在二维空间中对点坐标进行离散化,构建二维前缀和等辅助结构。
这些方法适合进阶使用,适合对大数据集进行快速查询。
示例说明
假设输入如下:
points = [[1,3],[3,3],[5,3],[2,2]]
queries = [[2,3,1],[4,3,1],[1,1,2]]
- 对第一个查询圆
(2,3,1)
:- 半径平方为 1。
- 检查每个点:
(1,3)
: 距离平方(1-2)^2 + (3-3)^2 = 1 <= 1
,计数 +1。(3,3)
: 距离平方1 <= 1
,计数 +1。(5,3)
: 距离平方9 > 1
,不计数。(2,2)
: 距离平方1 <= 1
,计数 +1。
- 结果:3 个点。
- 对第二个查询圆
(4,3,1)
:- 半径平方为 1。
- 检查点:
(1,3)
: 距离平方 9 > 1,不计数。(3,3)
: 距离平方 1 <= 1,计数 +1。(5,3)
: 距离平方 1 <= 1,计数 +1。(2,2)
: 距离平方 5 > 1,不计数。
- 结果:2 个点。
- 对第三个查询圆
(1,1,2)
:- 半径平方为 4。
- 检查点:
(1,3)
: 距离平方 4 <= 4,计数 +1。(3,3)
: 距离平方 8 > 4,不计数。(5,3)
: 距离平方 20 > 4,不计数。(2,2)
: 距离平方 2 <= 4,计数 +1。
- 结果:2 个点。
最终返回:
[3, 2, 2]
总结
本题是典型的空间查询问题,暴力解法直观且易实现,但在数据规模大时可能效率不足。合理利用空间数据结构可进一步优化。