1001. 网格照明题解
题目来源:1001. 网格照明
2022.02.08 每日一题
今年的第一道困难,可以采用哈希表来进行求解
根据题意,需要统计行、列、主对角线、副对角线四个方向的亮着的灯
由于行是 (0,a)、列是 (b,0)都可以通过变成一维的坐标,因此我们也可以将两个对角线转换成为一维的数组
在坐标系中,y 可以由 x 表示 $ y = kx +b $
本题中,只有主副两条对角线,因此 k 的值只有 ±1 两个值,因此我们可以通过一些简单的运算来将对角线转为一维变量
主对角线:$ x + y = x + (-x) + b_i=b_i $
副对角线:$ x - y = x - (x + b_j)=-b_j $
由此就将二维转变成为了一维的变量
具体思路:
建立四个哈希表统计各个方位点亮的灯,以及一个集合统计亮着的灯,如果点亮则在四个哈希表中添加对应的值,如果熄灭,则减去对应的值
具体代码以及注释如下
C++代码
class Solution {
public:
vector<int> gridIllumination(int n, vector<vector<int>> &lamps, vector<vector<int>> &queries) {
// 定义一个 dir 数组,记录周围九个方向的格子
vector<vector<int>> dir = {{-1, -1},
{-1, 0},
{-1, 1},
{0, 1},
{0, 0},
{0, -1},
{1, -1},
{1, 0},
{1, 1}};
// 定义四个哈希表,分别代表行、列、正对角线、反对角线,用来存储亮着的房间
unordered_map<int, int> Row, List, diagonal, antiDiagonal;
// 建立一个集合统计是亮的灯泡
set<pair<int, int>> O;
// 定义一个函数,令四个哈希表中的值加一
auto change = [&](int &x, int &y, int o) {
Row[x] += o, List[y] += o, diagonal[x - y] += o, antiDiagonal[x + y] += o;
};
// 遍历循环 lamps 数组统计点亮的灯
for (vector<int> &lamp: lamps) {
int x = lamp[0], y = lamp[1];
// 如果这个灯从未被点亮则在点亮灯的合集之中加入这盏灯
if (O.count(make_pair(x, y)) == 0) {
// 将未在集合中的灯加入到集合之中
O.insert(make_pair(x, y));
// 集合所在灯的四个哈希表之中都加一
change(x, y, 1);
}
}
// 定义一个结果数组
vector<int> res;
// 遍历 queries 数组,进行查询
for (vector<int> q: queries) {
// 将判断的结果放入 res 数组之中
res.push_back(Row[q[0]] || List[q[1]] || diagonal[q[0] - q[1]] || antiDiagonal[q[0] + q[1]]);
// 查找九个方位
for (vector<int> d: dir) {
int x = q[0] + d[0], y = q[1] + d[1];
// 如果存在亮着的灯就关闭,并且将对应亮的灯泡减一
if (O.count(make_pair(x, y))) {
O.erase(make_pair(x, y));
change(x, y, -1);
}
}
}
// 返回结果
return res;
}
};