原題
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;
}
};