暴力解法不可取,因为遍历数据导致时间与空间的浪费,出现运行超时等问题。
解题思路:
我们利用哈希表加快查找数据的效率。
先对数据进行去重处理(亮同一盏灯可能在 lamps
中多次列出,不会影响这盏灯处于 打开 状态。),然后利用哈希表来表示该灯泡是否被点亮。
r[i] 的值表示为这一行亮着的灯泡数,当我们点亮第 i 行灯泡时,直接 r[i] += 1,熄灭灯泡时 r[i] -= 1。
同理,列也可以用c[j]表示
反对角线上坐标的特点:x+y 在一条对角线上是一个恒定的数值
同理正对角线上的坐标特点是: x-y 在一条对角线上是一个恒定的数值
当某一行会被两个灯泡照亮时,r[i] = 3 (结果了三次 r[i] += 1)
那么只有三个灯泡都熄灭时,r[i] = 0,也就是结果三次 r[i] -= 1
因此,该点的8个方向上的值都为0时,说明这个灯泡是暗的
8个反向上只要有一个不为0,说明这个灯泡是亮的。
下面是该问题的具体解决代码:
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:
lamp.add((x,y))
# 构建哈希表
r[x]+=1 #行
c[y]+=1 #列
dia1[x-y]+=1 #对角线
dia2[x+y]+=1 #反对角线
result = list()
# 检查是否被照亮
for x,y in queries:
if r[x] or c[y] or dia1[x-y] or dia2[x+y]:
result.append(1)
else:
result.append(0)
# 删除四周的灯泡
for i in [-1,0,1]:
for j in [-1,0,1]:
nx = x+i
ny = y+j
# 判断该灯泡是否在lamp里面
if (nx,ny) in lamp:
# 更新哈希表
lamp.remove((nx,ny))
r[nx] -= 1 # 行
c[ny] -= 1 # 列
dia1[nx - ny] -= 1 # 对角线
dia2[nx + ny] -= 1 # 反对角线
return result
知识点:
有关defaultdict的用法:
注意事项:
代码中用集合存储被打开的灯(即 lamp=set() ),是因为集合基于哈希表实现,这使得它们能够在常数时间复杂度(O(1))内查找元素是否存在。相比之下,列表的查找操作需要遍历整个列表,其时间复杂度为O(n),其中n是列表中的元素数量。因此,当数据集较大时,集合的查找效率远高于列表。同理,除了查找操作外,集合还支持在常数时间复杂度内添加和删除元素,而列表是基于顺序表实现的,相比之下,列表的插入和删除操作(特别是在列表的开头或中间位置)可能需要移动多个元素,从而导致更高的时间复杂度。