2249. 统计圆内格点数目 ●●

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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值