点亮
的灯泡坐标点亮的灯泡
会照亮(上下左右,对角线,反对角线)上的灯泡。queries数组中有一些坐标,希望知道该坐标的灯泡是否是亮的(无论是点亮
还是照亮
都算亮)
查询操作:如果查询到的坐标的灯泡是亮的 返回1,否则返回 0
将查询坐标
附近的8个格子(如果在grid中)的灯泡熄灭,被熄灭的灯泡一定是点亮
的
该点被熄灭并不意味着它一定是暗的,因为可能被其他的灯泡照亮
如果蓝色和绿色的格子中有点亮的灯泡,就要熄灭它。
先从最容易想到的方法开始:
我们在点亮灯泡的时候,将它8个反向的灯泡全部照亮。
体现到代码就是将 grid矩阵赋值(0:暗;1:该点被照亮;2:该点是灯泡)
/*
我希望这函数能够进行点亮和熄灭操作(它们本质上是一样的)
isBlub:表示这次操作是不是点亮操作
row,col:是操作的坐标
*/
void controlLights(vector<vector<int>>& grid, int row, int col, bool isBlub){
int n = grid.size();
// 8 个反向上x,y的改变量
int dx[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
int state = isBlub?1:0; // 如果是点亮操作,接下来grid[x][y] 就会被赋值为1
grid[row][col] = isBlub?2:0; // 如果是点亮操作,赋值为2
for(int i=1;i<n;++i) {
for(int j=0;j<8;++j){
int x = row+i*dx[j];
int y = col+i*dy[j];
if(x>=0 && y>=0 && x<n && y<n &&grid[x][y]!=2)grid[x][y] = state;
}
}
}
接下来就是熄灭操作了
我们可以找出查询点周围的所有点亮的灯泡
放到lights数组中,并将他们熄灭
点亮的灯泡
照亮的灯泡点亮的灯泡
的坐标,并在每一次熄灭后,将剩余的灯泡重新进行点亮操作(使某些不应该熄灭的灯泡被照亮),这个set被命名为 blubs(灯泡)/*
这里row,col是查询的坐标
我希望通过这个函数将范围内的灯泡熄灭
所有点亮的灯泡的坐标
set> blubs;
*/
void turnOffLights(vector<vector<int>>& grid, int row, int col){
int n = grid.size();
vector<pair<int,int>> lights; // 周围存在的灯泡
if(grid[row][col]==2) lights.push_back({row,col});
for(int j=0;j<8;++j){
int x = row+dx[j];
int y = col+dy[j];
if(x>=0 && y>=0 && x<n && y<n && grid[x][y]==2) {
// 我们约定过 grid[x][y]=2时代表该点是点亮的灯泡
lights.push_back({x,y});
}
}
for(auto light : lights){
//灯泡要被熄灭了,从blubs中删掉它
blubs.erase(blubs.find(light));
controlLights(grid, light.first, light.second, false);
}
}
很遗憾这种暴力的方法是超时的,但仍有学习意义(至少思路没有错),这里给出代码。
class Solution {
public:
int dx[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
set<pair<int,int>> blubs;
void controlLights(vector<vector<int>>& grid, int row, int col, bool isBlub){
int n = grid.size();
int state = isBlub?1:0;
grid[row][col] = isBlub?2:0;
for(int i=1;i<n;++i) {
for(int j=0;j<8;++j){
int x = row+i*dx[j];
int y = col+i*dy[j];
if(x>=0 && y>=0 && x<n && y<n &&grid[x][y]!=2)grid[x][y] = state;
}
}
}
void turnOffLights(vector<vector<int>>& grid, int row, int col){
int n = grid.size();
vector<pair<int,int>> lights;
if(grid[row][col]==2) lights.push_back({row,col});
for(int j=0;j<8;++j){
int x = row+dx[j];
int y = col+dy[j];
if(x>=0 && y>=0 && x<n && y<n && grid[x][y]==2) {
lights.push_back({x,y});
}
}
for(auto light : lights){
blubs.erase(blubs.find(light));
controlLights(grid, light.first, light.second, false);
}
}
vector<int> gridIllumination(int n, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
vector<vector<int>> grid(n,vector<int>(n,0));
vector<int> ans;
for(auto coord : lamps){
controlLights(grid, coord[0], coord[1],true);
// lamps中的都是点亮的灯泡,加入blubs中
blubs.insert({coord[0], coord[1]});
}
for(auto coord : queries){
int row = coord[0];
int col = coord[1];
ans.push_back(grid[row][col]!=0);
turnOffLights(grid, row, col);
//每次熄灭灯泡后再点亮
for(auto i : blubs){
controlLights(grid, i.first, i.second, true);
}
}
return ans;
}
};
为什么暴力的方法会失败呢?
如何将一行/列 的坐标简化成一行,并且使用上哈希表呢?
unordered_map r
)接下来要解决对角线的表示
灯泡对角线
不同的特征,同时每条对角线上灯泡对角线
的特征是一样的(2,0) (0,2)
=> 2+0 = 1+1 <=(1,1)
)dia1[x-y]
和 dia2[x+y]
(dia是diagonal对角线的缩写)(x,y)
)时,dia[x-y] += 1
dia2[x+y] += 1
dia[x-y] -= 1
dia2[x+y] -= 1
如何表示某个灯泡的明暗呢?
一些小细节在代码注释中。
class Solution {
public:
vector<int> gridIllumination(int n, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
// 总灯泡,指的是所有的点亮的灯泡(不是照亮的)
set<pair<int,int>> lamp;
unordered_map<int,int> r;
unordered_map<int,int> c;
unordered_map<int,int> dia1;
unordered_map<int,int> dia2;
vector<int> ans;
for(auto item: lamps){
int x = item[0];
int y = item[1];
pair<int,int> xy = {x,y};
/*
这个if判断绝不能省去,因为题目说可能会有重复的灯泡的坐标。
那么同一盏灯不应该照亮周围的灯泡两次
*/
if(lamp.find(xy)==lamp.end()){
lamp.insert(xy);
r[x] += 1;
c[y] += 1;
dia1[x-y] += 1;
dia2[x+y] += 1;
}
}
for(auto query : queries){
int row = query[0];
int col = query[1];
// 只要有一个反向上被照亮过,就说明这个灯泡是亮的
r[row] || c[col] || dia1[row-col] || dia2[row+col] ? ans.push_back(1) : ans.push_back(0);
for(int x = row-1; x<row+2; ++x){
for(int y=col-1; y<col+2; ++y){
// 如果(x,y) 是总灯泡中的某一个,就要消除它照亮的灯泡
if(x<0 || y<0 || x>n || y>n || lamp.find({x,y})==lamp.end()) continue;
// 这个灯泡已经被删除了,从总灯泡中移除
lamp.erase(lamp.find({x,y}));
r[x] -= 1;
c[y] -= 1;
dia1[x-y] -= 1;
dia2[x+y] -= 1;
}
}
}
return ans;
}
};
from collections import defaultdict
class Solution(object):
def gridIllumination(self, n, lamps, queries):
"""
:type n: int
:type lamps: List[List[int]]
:type queries: List[List[int]]
:rtype: List[int]
"""
lamp = set()
r, c, dia1, dia2, ans = defaultdict(int), defaultdict(int) ,defaultdict(int), defaultdict(int), list()
for x,y in lamps:
if (x,y) in lamp:
continue
lamp.add((x,y))
r[x] += 1
c[y] += 1
dia1[x-y] += 1
dia2[x+y] += 1
for i,j in queries:
if r[i] or c[j] or dia1[i-j] or dia2[i+j]:
ans.append(1)
else:
ans.append(0)
for x in range(i-1, i+2):
for y in range(j-1, j+2):
if x<0 or y<0 or x>=n or y>=n or (x,y) not in lamp:
continue
lamp.remove((x,y))
r[x] -= 1
c[y] -= 1
dia1[x-y] -= 1
dia2[x+y] -= 1
return ans
from collections import defaultdict
class Solution:
def gridIllumination(self, N: int, lamps: List[List[int]], queries: List[List[int]]) -> List[int]:
r, c, dia1, dia2 = defaultdict(int), defaultdict(int) ,defaultdict(int), defaultdict(int)
lamp = set()
for x, y in lamps:
if (x,y) not in lamp:
r[x] += 1
c[y] += 1
dia1[x+y] += 1
dia2[x-y] += 1
lamp.add((x, y))
res = list()
for i, j in queries:
if r[i] or c[j] or dia1[i + j] or dia2[i - j]:
res.append(1)
else:
res.append(0)
for x in [-1, 0, 1]:
for y in [-1, 0, 1]:
nx = x + i
ny = y + j
if (nx, ny) in lamp:
r[nx] -= 1
c[ny] -= 1
dia1[nx+ny] -= 1
dia2[nx-ny] -= 1
lamp.remove((nx, ny))
return res