2249. 统计圆内格点数目 ●●
描述
给你一个二维整数数组 circles ,其中 circles[i] = [xi, yi, ri] 表示网格上圆心为 (xi, yi) 且半径为 ri 的第 i 个圆,返回出现在 至少一个 圆内的 格点数目 。
注意:
- 格点 是指整数坐标对应的点。
- 圆周上的点 也被视为出现在圆内的点。
示例
输入:circles = [[2,2,1]]
输出:5
解释:
给定的圆如上图所示。
出现在圆内的格点为 (1, 2)、(2, 1)、(2, 2)、(2, 3) 和 (3, 2),在图中用绿色标识。
像 (1, 1) 和 (1, 3) 这样用红色标识的点,并未出现在圆内。
因此,出现在至少一个圆内的格点数目是 5 。
输入:circles = [[2,2,2],[3,4,1]]
输出:16
解释:
给定的圆如上图所示。
共有 16 个格点出现在至少一个圆内。
其中部分点的坐标是 (0, 2)、(2, 0)、(2, 4)、(3, 2) 和 (4, 4) 。
题解
1. 哈希表记录有效格点
从每个圆的左上角遍历到右下角坐标,判断点到圆心的距离与半径的关系,若不在圆内则忽略,若在圆内且哈希表查询无果则记录,并计数。
class Solution {
public:
int countLatticePoints(vector<vector<int>>& circles) {
unordered_set<int> hash;
int ans = 0;
for(auto circle : circles){
int ox = circle[0], oy = circle[1], r = circle[2];
for(int dx = -r; dx <= r; ++dx){ // 从每个圆的左上角遍历到右下角坐标
for(int dy = - r; dy <= r; ++dy){
if(dx*dx + dy*dy <= r*r && hash.count((ox+dx) * 10000 + oy+dy) == 0){
++ans;
hash.emplace((ox+dx) * 10000 + oy+dy); // 每个点具有唯一的 x * 10000 + y
}
}
}
}
return ans;
}
};
2. 双指针 + 差分数组统计
class Solution {
public:
int countLatticePoints(vector<vector<int>>& circles) {
int maxx = 0, maxy = 0;
for(auto& c : circles) {
maxx = max(maxx, c[0] + c[2]);
maxy = max(maxy, c[1] + c[2]);
}
//这里是寻找x,y的最大值,便于之后开差分数组
//每一行都是独立的差分数组
int d[maxy + 2][maxx + 2];
memset(d, 0, sizeof(d));
for(auto& c : circles) {
//计算上半圆,上半圆从上向下一条条横线,对于一个圆,x只遍历一次,所以是O(NX)
//对于y也是遍历一次,所以是O(Ny),总和是O(NX+NY)
for(int y = c[1] + c[2], x1 = c[0], x2 = c[0]; y >= c[1]; --y) {
while((x1 - c[0]) * (x1 - c[0]) + (y - c[1]) * (y - c[1]) <= c[2] * c[2]) --x1;
while((x2 - c[0]) * (x2 - c[0]) + (y - c[1]) * (y - c[1]) <= c[2] * c[2]) ++x2;
//差分数组,x1+1是因为刚刚出循环的时候多--了一次,补上
d[y][x1+1]++;
//x2不需要-1,因为差分数组本来就是要+1的
d[y][x2]--;
}
for(int y = c[1] - c[2], x1 = c[0], x2 = c[0]; y < c[1]; ++y) {
while((x1 - c[0]) * (x1 - c[0]) + (y - c[1]) * (y - c[1]) <= c[2] * c[2]) --x1;
while((x2 - c[0]) * (x2 - c[0]) + (y - c[1]) * (y - c[1]) <= c[2] * c[2]) ++x2;
d[y][x1+1]++;
d[y][x2]--;
}
}
int res = 0;
for(int y = 0; y <= maxy; ++y) {
for(int x = 0, cur = 0; x <= maxx; ++x) {//对于每一行,差分数组查看当前位置是否被覆盖到。
cur += d[y][x];
if(cur > 0) res++;
}
}
return res;
}
};