LeetCode 1001. Grid Illumination
作者:互联网
原题
On a N x N grid of cells, each cell (x, y) with 0 <= x < N and 0 <= y < N has a lamp.
Initially, some number of lamps are on. lamps[i] tells us the location of the i-th lamp that is on. Each lamp that is on illuminates every square on its x-axis, y-axis, and both diagonals (similar to a Queen in chess).
For the i-th query queries[i] = (x, y), the answer to the query is 1 if the cell (x, y) is illuminated, else 0.
After each query (x, y) [in the order given by queries], we turn off any lamps that are at cell (x, y) or are adjacent 8-directionally (ie., share a corner or edge with cell (x, y).)
Return an array of answers. Each value answer[i] should be equal to the answer of the i-th query queries[i].
Example 1:
Input: N = 5, lamps = [[0,0],[4,4]], queries = [[1,1],[1,0]]
Output: [1,0]
Explanation:
Before performing the first query we have both lamps [0,0] and [4,4] on.
The grid representing which cells are lit looks like this, where [0,0] is the top left corner, and [4,4] is the bottom right corner:
1 1 1 1 1
1 1 0 0 1
1 0 1 0 1
1 0 0 1 1
1 1 1 1 1
Then the query at [1, 1] returns 1 because the cell is lit. After this query, the lamp at [0, 0] turns off, and the grid now looks like this:
1 0 0 0 1
0 1 0 0 1
0 0 1 0 1
0 0 0 1 1
1 1 1 1 1
Before performing the second query we have only the lamp [4,4] on. Now the query at [1,0] returns 0, because the cell is no longer lit.
Note:
1 <= N <= 10^9
0 <= lamps.length <= 20000
0 <= queries.length <= 20000
lamps[i].length == queries[i].length == 2
分析
给定N的范围从1到10^9,如果直接拍脑门构建NxN大的方阵来对所有数据进行存储有点不太现实,再者,构建好NxN方阵之后,其存着的太多的0并没有太多的意义。因此我们需要构造合适的数据结构对题目中提到的关系进行存储。
关系分析
- 灯以及其照亮的点,这个关系是双向的,因为我们需要
- 根据照亮的点判断关哪个灯
- 关灯后熄灭其被照亮的点
- 查询的位置与被灯照亮的位置,需要被用来进行查找,因此这里的关系是单向
- 查询的位置周围8个格与灯的位置,因为在进行一次查询之后,如果周围有灯泡,需要将灯泡熄灭,这个关系也是一个单向的关系
- 最后,由于一个位置可能被多个灯照亮,因此被照亮的位置与灯存在一对多的关系
数据表示及算法流程
数据表示
在对涉及得到的位置信息进行分析之后,我们可以构造相应的数据结构来对以上的数据建立联系。
- map<pair<int, int>, int > point_frep, 用map来建立从被照亮的点与灯的关系,**pair<int, int>**是被照亮的位置,后面的int 是该位置上的灯泡数。
- map<int, int>x_frep, 表示x行被照亮,第二个int表示被几个灯光照亮
- map<int, int>y_frep,表示y列被照亮,第二个int表示被几个灯光照亮
- map<int, int>sum_frep, map<int, int> diff_frep分别表示斜着的x + y,x-y行被照亮,第二个int表示被几个灯光照亮。
关于第四个关系可以由以下的图简短说明:
当灯的位置处于(0,2)时可以发现
1. 被照亮的绿色位置的值均满足(x+y = 2)
2. 被照亮的红色位置的值均满足(x- y = -2)
3.
因此,可以很方便的根据给出点的坐标来判断是否被某灯照亮。(其实是分别处于x+y=a, x-y=b直线上)
流程
- 先对lamps进行遍历,构造提到的灯与被照亮位置的关系
- 记录每个位置灯的数量
- 更新其照亮的位置
- 遍历queries
- 根据其坐标判断是否被照亮
- 周围8个格子是否存在灯泡,根据point_frep来判断其值,如果存在灯泡
- “熄灭”被照亮的行、列
- 该位置灯泡数减一
他山之石,可以攻玉(别人的答案)
在提交之后可以看到别人提交的答案,看完后再看看自己的代码便更觉得羞涩难挡,因此去掉了贴自己代码这一步,转而分析别人代码。
作者: @neal_wu
class Solution {
public:
vector<int> gridIllumination(int N, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
int L = lamps.size(), Q = queries.size();
map<pair<int, int>, int> point_frep;
map<int, int> x_frep, y_frep, sum_frep, diff_frep;
for (auto lamp : lamps) {
int x = lamp[0], y = lamp[1];
point_frep[make_pair(x, y)]++;
x_frep[x] ++;
y_frep[y] ++;
sum_frep[x + y] ++;
diff_frep[x - y] ++;
}
vector<int> res;
for (auto query : queries) {
int x = query[0], y = query[1];
bool ans = x_frep[x] > 0 || y_frep[y] > 0 || sum_frep[x + y] > 0 || diff_frep[x - y] > 0;
res.push_back(ans ? 1 : 0);
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
int nx = x + dx, ny = y + dy;
int freq = point_frep[make_pair(nx, ny)];
if (freq > 0) {
x_frep[nx] -= freq;
y_frep[ny] -= freq;
sum_frep[nx + ny] -= freq;
diff_frep[nx - ny] -= freq;
point_frep[make_pair(nx, ny)] -= freq;
}
}
}
}
return res;
}
};
标签:照亮,int,queries,Grid,query,Illumination,frep,LeetCode,lamps 来源: https://blog.csdn.net/likewind1993/article/details/87998850