1001.网格照明

139 阅读2分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。

每日刷题第41天 2021.02.08

1001.网格照明

题目

  • 在大小为 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 image.png
输入: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 。然后,关闭红色方框中的所有灯。

image.png

1 次查询检查 grid[1][0] 是否被照亮(蓝色方框)。该单元格没有被照亮,所以 ans[1] = 0 。然后,关闭红色矩形中的所有灯。

image.png

  • 示例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 即可
  • lampsqueries 的长度分别为l q,需要遍历一次 lamps 记录状态,时间复杂度为 O(l),需要遍历一次queries进行查询,时间复杂度为 O(q),总时间复杂度为 O(l + q)
  • 需要用 1 Set 记录单元格是否有灯,需要用 4Map 记录四线上灯的数量,总空间复杂度为 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
};