leetcode刷题记录-1001. 网格照明

652 阅读4分钟

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

前言

今日的题目为困难,但是弄懂题目的意思,这道题顶多就算是中等题。可能是因为困难题提交的人不多,所以今日提交双击败100%。

每日一题

今天的每日一题 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*n大小的矩阵,然后再给一个数组保存着矩阵中对应灯的位置,

  1. 第一个问题就是,我们有了灯的位置,要怎么来保存灯所发出的灯光的位置。我们可以用横,竖,正对角线,反对角线,四个哈希表来保存灯光,比方说在(1,1)这个位置有一盏灯,那么我们就在横的 y 哈希表中,保存下(1,1),表示y = 1的这个坐标上的灯光都为亮的,以此类推,我们还可以用 x 哈希表来保存竖直方向的 x 坐标,用 diagonal 哈希表来保存对角线的坐标,至于对角线方向的key根据对角线的方程性质,我们可以用(x - y)保存下来,反对角线就相反,用(x + y)保存下来。

  2. 保存了四个方向的灯光之后,我们还需要保存下灯所在的位置,题目中有提到,一盏灯可能会多次出现,但是都会是打开的状态,所以我们用一个 set 表来保存下灯的位置,灯的位置就用(x,y)的坐标格式来保存,我们可以创建一个coordinate函数,用于传入x,y,然后返回拼接后的 x,y:

const coordinate = (x, y) => {
    return  x + ',' + y;
};
  1. 这样我们就成功存下了灯和灯光,接着就是需要通过传入的第二个数组 queries 来判断当前位置是否有灯光并且关闭它周围九宫格的灯。

  2. 因为题目最后会返回一个数组,这个数组的长度和 queries 相等相等,并且每个位置上为 0 或者 1 就代表着当前位置是否有灯光。那么,我们可以新建一个长度和 queries 相等的数组 ans,并且都先用 0 赋值,接着去遍历我们的 queries 数组,当当前点上有灯光的话,就将 ans 对应位置上的值变为1,然后去关闭周围九宫格的灯。

  3. 首先我们需要去遍历 queries 传入点位的周围九宫格,将传入的 queries 的横坐标设为 queriesX,纵坐标为 queriesY,这样我们就可以通过一个双重循环来遍历周围九宫格:

for (let x = queriesX - 1; x < queriesX + 2; x++) {
    for (let y = queriesY - 1; y < queriesY + 2; y++) {
        ...
    }
}
  1. 遍历的过程中就可以去判断,当前位置是否超出 n*n 的矩阵,每超出再去判断当前位置是否存在灯。
if (x < 0 || y < 0 || x >= n || y >= n || !points.has(coordinate(x, y))) {
    continue;
}
  1. 当前位置没有超出矩阵并且存在一盏灯,那么就将这盏灯从灯的表中删除,并且对应的四个方向的灯光数都要减一:
points.delete(coordinate(x, y));
row.set(x, row.get(x) - 1);
col.set(y, col.get(y) - 1);
diagonal.set(x - y, diagonal.get(x - y) - 1);
antiDiagonal.set(x + y, antiDiagonal.get(x + y) - 1);
  1. 最后将等到的ans数组返回就是题目需要的答案。
/**
 * @param {number} n
 * @param {number[][]} lamps
 * @param {number[][]} queries
 * @return {number[]}
 */
 var gridIllumination = function(n, lamps, queries) {
    const row = new Map();
    const column = new Map();
    const diagonal = new Map();
    const antiDiagonal = new Map();
    const lights = new Set();
    for (const lamp of lamps) {
        if (lights.has(coordinate(lamp[0], lamp[1]))) {
            continue;
        }
        lights.add(coordinate(lamp[0], lamp[1]));
        row.set(lamp[0], (row.get(lamp[0]) || 0) + 1);
        column.set(lamp[1], (column.get(lamp[1]) || 0) + 1);
        diagonal.set(lamp[0] - lamp[1], (diagonal.get(lamp[0] - lamp[1]) || 0) + 1);
        antiDiagonal.set(lamp[0] + lamp[1], (antiDiagonal.get(lamp[0] + lamp[1]) || 0) + 1);
    }
    const ans = new Array(queries.length).fill(0);
    for (const [i, [queriesX, queriesY]] of queries.entries()) {
        if (row.get(queriesX) || column.get(queriesY) || diagonal.get(queriesX - queriesY) || antiDiagonal.get(queriesX + queriesY)) {
            ans[i] = 1;
        }
        for (let x = queriesX - 1; x < queriesX + 2; x++) {
            for (let y = queriesY - 1; y < queriesY + 2; y++) {
                if (x < 0 || y < 0 || x >= n || y >= n || !lights.has(coordinate(x, y))) {
                    continue;
                }
                lights.delete(coordinate(x, y));
                row.set(x, row.get(x) - 1);
                column.set(y, column.get(y) - 1);
                diagonal.set(x - y, diagonal.get(x - y) - 1);
                antiDiagonal.set(x + y, antiDiagonal.get(x + y) - 1);
            }
        }
    }
    return ans;
}

const coordinate = (x, y) => {
    return  x + ',' + y;
};

image.png