「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。
每日刷题第41天 2021.02.08
1001.网格照明
- leetcode原题链接:leetcode-cn.com/problems/gr…
- 难度:困难
- 方法
题目
- 在大小为 n x n 的网格 grid 上,每个单元格都有一盏灯,最初灯都处于 关闭 状态。
- 给你一个由灯的位置组成的二维数组 lamps ,其中 lamps[i] = [rowi, coli] 表示 打开 位于 grid[rowi][coli] 的灯。即便同一盏灯可能在 lamps 中多次列出,不会影响这盏灯处于 打开 状态。
- 当一盏灯处于打开状态,它将会照亮 自身所在单元格 以及同一 行 、同一 列 和两条 对角线 上的 所有其他单元格 。
- 另给你一个二维数组 queries ,其中 queries[j] = [rowj, colj] 。对于第 j 个查询,如果单元格 [rowj, colj] 是被照亮的,则查询结果为 1 ,否则为 0 。在第 j 次查询之后 [按照查询的顺序] ,关闭 位于单元格 grid[rowj][colj] 上及相邻 8 个方向上(与单元格 grid[rowi][coli] 共享角或边)的任何灯。
- 返回一个整数数组 ans 作为答案, ans[j] 应等于第 j 次查询 queries[j] 的结果,1 表示照亮,0 表示未照亮。
示例
- 示例1
输入:n = 5, lamps = [[0,0],[4,4]], queries = [[1,1],[1,0]]
输出:[1,0]
解释:最初所有灯都是关闭的。在执行查询之前,打开位于 [0, 0] 和 [4, 4] 的灯。第 0 次查询检查 grid[1][1] 是否被照亮(蓝色方框)。该单元格被照亮,所以 ans[0] = 1 。然后,关闭红色方框中的所有灯。
第 1 次查询检查 grid[1][0] 是否被照亮(蓝色方框)。该单元格没有被照亮,所以 ans[1] = 0 。然后,关闭红色矩形中的所有灯。
- 示例2
输入: n = 5, lamps = [[0,0],[4,4]], queries = [[1,1],[1,1]]
输出: [1,1]
- 示例3
输入: n = 5, lamps = [[0,0],[0,4]], queries = [[0,4],[0,1],[1,4]]
输出: [1,1,0]
提示
1 <= n <= 109
0 <= lamps.length <= 20000
0 <= queries.length <= 20000
lamps[i].length == 2
0 <= rowi, coli < n
queries[j].length == 2
0 <= rowj, colj < n
解法
思路
- 网格边长
n最大为1e9,模拟是不现实的,考虑其他方法; - 可以看到一个灯只会影响它所在的行、列以及两条对角线上的位置结果。
- 在查询
[r,c]位置的时候,我们只需要知道该位置所在的行、列或两条对角线是否存在亮着的灯即可,存在则查询结果为1,不存在则为0; - 那么问题转化为:给定一个位置
[r,c],如何快速确定它是否在某个亮灯的行、列或对角线上。不难想到,如果我们把全部的亮着的行、列和对角线都通过哈希表记录下来,在查询的时候直接在表中进行查找即可;- 行和列可以用自身的编号在哈希表中存储,对角线我们采用下述方式存储:
- 对于左下-右上对角线,我们将其归化到左下角,并按序号存储;
- 对于右下-左上对角线,我们将其归化到左上角,并按序号存储;
- 每一个哈希表,键名为行、列或对角线序号,对应的键值为这个行、列、对角线上的亮着的灯泡个数。对于查询过的位置
[r,c],我们遍历其邻接的位置,如果存在亮着的灯,需要将其熄灭,操作为在对应哈希表中将对应位置值-1; - 注意:
lamps存在重复的灯,需要先去重。
类似八皇后题目
- 如果从某个单元格出发,查找
8个方向上是否有灯, 明显会超时。问题关键点在于,如何快速判断单元格是否被照亮 - 可以通过预处理,提前记录下行,列,斜线上有多少盏灯,查询的时候只要判断单元格所在四线上是否有灯即可。可以参考这题
51. N 皇后 - 查询时发现相邻 1 格范围内有灯,将灯移除,并将所在四线上灯的数量减 1 即可
- 设
lamps与queries的长度分别为l和q,需要遍历一次lamps记录状态,时间复杂度为O(l),需要遍历一次queries进行查询,时间复杂度为O(q),总时间复杂度为O(l + q) - 需要用
1个Set记录单元格是否有灯,需要用4个Map记录四线上灯的数量,总空间复杂度为O(5l),即O(l)
/**
* @param {number} n
* @param {number[][]} lamps
* @param {number[][]} queries
* @return {number[]}
*/
const hash = (i, j) => `${i}-${j}`
const dirs = [[0, 0], [1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
var gridIllumination = function(n, lamps, queries) {
let point = new Set()
let xS = new Map()
let yS = new Map()
let xaS = new Map()
let yaS = new Map()
for (const lamp of lamps) {
const x = lamp[0]
const y = lamp[1]
if (point.has(hash(x, y))) continue
point.add(hash(x, y))
xS.set(x, (xS.get(x) || 0) + 1)
yS.set(y, (yS.get(y) || 0) + 1)
xaS.set(x+y, (xaS.get(x+y) || 0) + 1)
yaS.set(y-x, (yaS.get(y-x) || 0) + 1)
}
let res = []
for (const query of queries) {
const x = query[0]
const y = query[1]
if ((xS.has(x) && xS.get(x) > 0) || (yS.has(y) && yS.get(y) > 0) || (xaS.has(x+y) && xaS.get(x+y) > 0) || (yaS.has(y-x) && yaS.get(y-x) > 0)) {
res.push(1)
} else {
res.push(0)
}
for (const dir of dirs) {
let newX = x + dir[0]
let newY = y + dir[1]
if (newX >= 0 && newX < n && newY >= 0 && newY < n && point.has(hash(newX, newY))) {
point.delete(hash(newX, newY))
xS.set(newX, (xS.get(newX) || 0) - 1)
yS.set(newY, (yS.get(newY) || 0) - 1)
xaS.set(newX+newY, (xaS.get(newX+newY) || 0) - 1)
yaS.set(newY-newX, (yaS.get(newY-newX) || 0) - 1)
}
}
}
return res
};