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並沒有太多的意義。因此我們需要構造合適的數據結構對題目中提到的關係進行存儲。

關係分析

  1. 燈以及其照亮的點,這個關係是雙向的,因爲我們需要
    • 根據照亮的點判斷關哪個燈
    • 關燈後熄滅其被照亮的點
  2. 查詢的位置與被燈照亮的位置,需要被用來進行查找,因此這裏的關係是單向
  3. 查詢的位置周圍8個格與燈的位置,因爲在進行一次查詢之後,如果周圍有燈泡,需要將燈泡熄滅,這個關係也是一個單向的關係
  4. 最後,由於一個位置可能被多個燈照亮,因此被照亮的位置與燈存在一對多的關係

數據表示及算法流程

數據表示

在對涉及得到的位置信息進行分析之後,我們可以構造相應的數據結構來對以上的數據建立聯繫。

  1. map<pair<int, int>, int > point_frep, 用map來建立從被照亮的點與燈的關係,**pair<int, int>**是被照亮的位置,後面的int 是該位置上的燈泡數。
  2. map<int, int>x_frep, 表示x行被照亮,第二個int表示被幾個燈光照亮
  3. map<int, int>y_frep,表示y列被照亮,第二個int表示被幾個燈光照亮
  4. 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直線上)
在這裏插入圖片描述

流程

  1. 先對lamps進行遍歷,構造提到的燈與被照亮位置的關係
    1. 記錄每個位置燈的數量
    2. 更新其照亮的位置
  2. 遍歷queries
    1. 根據其座標判斷是否被照亮
    2. 周圍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;
	}
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章