Medium
题目描述
给你一个二维整数数组 circles ,其中 circles[i] = [xi, yi, ri] 表示网格上画的第 i 个圆的圆心 (xi, yi) 和半径 ri ,返回出现在至少一个圆内的格点数目。
注意:
- 格点是指整数坐标对应的点。
- 圆周上的点也被认为是在圆内。
示例 1:
输入:circles = [[2,2,1]]
输出:5
解释:
给定的圆如上图所示。
出现在圆内的格点为 (1, 2)、(2, 1)、(2, 2)、(2, 3) 和 (3, 2),在图中用绿色标识。
像 (1, 1) 和 (1, 3) 这样用红色标识的点,并不在圆内。
因此,出现在至少一个圆内的格点数目是 5。
示例 2:
输入:circles = [[2,2,2],[3,4,1]]
输出:16
解释:
给定的圆如上图所示。
共有 16 个格点出现在至少一个圆内。
其中部分点的坐标是 (0, 2)、(2, 0)、(2, 4)、(3, 2) 和 (4, 4)。
提示:
1 <= circles.length <= 200circles[i].length == 31 <= xi, yi <= 1001 <= ri <= min(xi, yi)
解题思路
解题思路
这道题需要统计在至少一个圆内的格点数量。我们可以使用以下方法:
方法一:枚举 + 集合去重(推荐)
确定搜索范围:首先计算所有圆能覆盖的最小和最大坐标范围,这样可以减少不必要的枚举。
枚举所有可能的格点:在确定的范围内枚举每个整数坐标点。
检查点是否在圆内:对于每个格点,检查它是否在至少一个圆内。判断点
(x, y)是否在圆心(cx, cy)半径为r的圆内,只需检查:(x - cx)² + (y - cy)² ≤ r²使用集合去重:由于同一个格点可能在多个圆内,使用 Set 数据结构自动去重。
优化点:
- 通过计算所有圆的边界来确定搜索范围,避免枚举过多不必要的点
- 一旦发现格点在某个圆内,就可以加入结果集,无需继续检查其他圆
时间复杂度主要取决于搜索范围的大小和圆的数量,在给定约束下是可接受的。
代码实现
class Solution {
public:
int countLatticePoints(vector<vector<int>>& circles) {
// 确定搜索范围
int minX = 200, maxX = 0, minY = 200, maxY = 0;
for (auto& circle : circles) {
int x = circle[0], y = circle[1], r = circle[2];
minX = min(minX, x - r);
maxX = max(maxX, x + r);
minY = min(minY, y - r);
maxY = max(maxY, y + r);
}
set<pair<int, int>> latticePoints;
// 枚举所有可能的格点
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
// 检查点(x, y)是否在至少一个圆内
for (auto& circle : circles) {
int cx = circle[0], cy = circle[1], r = circle[2];
if ((x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r) {
latticePoints.insert({x, y});
break; // 找到一个包含该点的圆就足够了
}
}
}
}
return latticePoints.size();
}
};
class Solution:
def countLatticePoints(self, circles: List[List[int]]) -> int:
# 确定搜索范围
min_x = min(x - r for x, y, r in circles)
max_x = max(x + r for x, y, r in circles)
min_y = min(y - r for x, y, r in circles)
max_y = max(y + r for x, y, r in circles)
lattice_points = set()
# 枚举所有可能的格点
for x in range(min_x, max_x + 1):
for y in range(min_y, max_y + 1):
# 检查点(x, y)是否在至少一个圆内
for cx, cy, r in circles:
if (x - cx) ** 2 + (y - cy) ** 2 <= r ** 2:
lattice_points.add((x, y))
break # 找到一个包含该点的圆就足够了
return len(lattice_points)
public class Solution {
public int CountLatticePoints(int[][] circles) {
// 确定搜索范围
int minX = 200, maxX = 0, minY = 200, maxY = 0;
foreach (var circle in circles) {
int x = circle[0], y = circle[1], r = circle[2];
minX = Math.Min(minX, x - r);
maxX = Math.Max(maxX, x + r);
minY = Math.Min(minY, y - r);
maxY = Math.Max(maxY, y + r);
}
var latticePoints = new HashSet<(int, int)>();
// 枚举所有可能的格点
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
// 检查点(x, y)是否在至少一个圆内
foreach (var circle in circles) {
int cx = circle[0], cy = circle[1], r = circle[2];
if ((x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r) {
latticePoints.Add((x, y));
break; // 找到一个包含该点的圆就足够了
}
}
}
}
return latticePoints.Count;
}
}
var countLatticePoints = function(circles) {
// 确定搜索范围
let minX = Math.min(...circles.map(([x, y, r]) => x - r));
let maxX = Math.max(...circles.map(([x, y, r]) => x + r));
let minY = Math.min(...circles.map(([x, y, r]) => y - r));
let maxY = Math.max(...circles.map(([x, y, r]) => y + r));
const latticePoints = new Set();
// 枚举所有可能的格点
for (let x = minX; x <= maxX; x++) {
for (let y = minY; y <= maxY; y++) {
// 检查点(x, y)是否在至少一个圆内
for (const [cx, cy, r] of circles) {
if ((x - cx) * (x - cx) + (y - cy) * (y - cy) <= r * r) {
latticePoints.add(`${x},${y}`);
break; // 找到一个包含该点的圆就足够了
}
}
}
}
return latticePoints.size;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(W × H × N),其中 W 和 H 分别是搜索范围的宽度和高度,N 是圆的数量。在最坏情况下,W 和 H 约为 200,N 最大为 200 |
| 空间复杂度 | O(W × H),用于存储去重后的格点坐标,最坏情况下所有格点都在某个圆内 |