力扣1001——网格照明(哈希)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解题思路

数据量很大,模拟实际场景不现实;
因为灯可以直接点亮其所在行列和对角线,所以可以用哈希存储哪些行列对角线有亮光;
总体分为三部分,1、统计所有亮光所在信息;2、对每次查询,看所在地是否亮;3、关掉查询地范围内的灯
第一步:统计亮光
这里可以先对灯泡去重,然后记录灯泡点亮的行列和两条对角线
灯泡(x,y)所在行列不必多说,其所在对角线可找规律发现,左右对角线编号分别为 n - (y-x) 和 x + y + 1;从1到2n-1;用哈希表统计;
第二步:判断
对每次查询,看查询点所在的行列对角线是否在亮光的哈希表中,是的话该次为1;
第三步:关灯
遍历查询点一周的九个位置,如果有灯,则将灯清出灯的集合,并清除掉该灯的照明效果;

对于照明效果的清除,可以通过哈希计数实现,在统计时,不光要统计哪些地方亮,还要统计导致这些地方亮的灯的个数,在关灯时相应的减去该个数即可;

总体复杂度O(N)

代码

class Solution {
private:
    set<pair<int, int>> la;
    vector<pair<int, int>> dir;
    vector<unordered_map<int, int>> light = vector<unordered_map<int, int>>(4);
    int N;
public:
    void turnoff(int x, int y) {
        for(auto [dx, dy] : dir) {
            int nx = x + dx, ny = y + dy;
            if(nx < 0 || nx >= N || ny < 0 || ny >= N) continue;
            if(la.count({nx, ny})) {
                la.erase({nx, ny});
                light[0][nx]--;
                light[1][ny]--;
                light[2][N - (ny - nx)]--;
                light[3][nx + ny + 1]--;               
            }
        }
        return ;
    }
    vector<int> gridIllumination(int n, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
        //行,列,左右对角线编号(n - (y-x) 和 x+y+1
        int qn = queries.size();
        N = n;
        vector<int> ans(qn, 0);
        for(int i = -1; i <= 1; i++) {
            for(int j = -1; j <= 1; j++) {
                dir.push_back({i, j});
            }
        }
        for(auto l : lamps) {
            int x = l[0], y = l[1];
            if(la.count({x, y})) continue;
            la.insert({x, y});
            light[0][x]++;
            light[1][y]++;
            light[2][n - (y - x)]++;
            light[3][x + y + 1]++;
        }
        for(int i = 0; i < qn; i++) {
            int x = queries[i][0], y = queries[i][1];
            int left = n - (y - x), right = x + y + 1;
            if(light[0][x] > 0 || light[1][y] > 0 || light[2][left] > 0 || light[3][right] > 0) {
                ans[i] = 1;
            }
            turnoff(x, y);            
        }
        return ans;
    }
}; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值