JavaInterview JavaInterview
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)

『Java面试+Java学习』
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)
  • 指南
  • 简历

  • Java

  • 面试

  • 算法

  • algorithm
  • leetcode
JavaInterview.cn
2024-09-22
目录

网格照明Java

文章发布较早,内容可能过时,阅读注意甄别。

# 题目

在大小为 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:

illu_1.jpg

输入: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 。然后,关闭红色方框中的所有灯。

illu_step1.jpg

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

illu_step2.jpg

示例 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

# 思路

四个哈希表分别表示行、列、正对角线、反对角线的灯的数量

# 解法

class Solution {
    public int[] gridIllumination(int n, int[][] lamps, int[][] queries) {
        //四个哈希表分别表示行、列、正对角线、反对角线的灯的数量
        Map<Integer, Integer> rows = new HashMap<>();  
        Map<Integer, Integer> columns = new HashMap<>(); 
        Map<Integer, Integer> diagonal = new HashMap<>(); 
        Map<Integer, Integer> antiDiagonal = new HashMap<>(); 
        //一个set存放所有的点,记录开灯情况,便于在查询过程中检查周围8个是否开灯
        Set<String> points = new HashSet<>();
        //遍历lamps二维数组,对四个map进行填充,对set中开灯情况进行记录
        for(int[] lamp : lamps){
            //如果这个lamp坐标值已经被记录在points集合中,跳过
            if(!points.add(lamp[0] + "+" + lamp[1])) continue; 
            //否则对四个哈希表进行操作
            rows.put(lamp[0], rows.getOrDefault(lamp[0],0) + 1);
            columns.put(lamp[1], columns.getOrDefault(lamp[1],0) + 1);
            //这里采取对角线与x轴交点的坐标值作为该条对角线的key值
            diagonal.put(lamp[0]-lamp[1], diagonal.getOrDefault(lamp[0] - lamp[1], 0) + 1);
            antiDiagonal.put(lamp[0]+lamp[1], antiDiagonal.getOrDefault(lamp[0] + lamp[1], 0) + 1);
        }
        //开始查询
        int[] res = new int[queries.length];
        for(int i = 0; i < queries.length; i++){
            int row = queries[i][0], column = queries[i][1];
            //判断该点的行、列、两条对角线是否有灯,只要有一条线上有灯亮就置1
            if(rows.getOrDefault(row, 0) > 0) res[i] = 1;
            else if(columns.getOrDefault(column,0) > 0) res[i] = 1;
            else if(diagonal.getOrDefault(row - column, 0) > 0) res[i] = 1;
            else if(antiDiagonal.getOrDefault(row + column, 0) > 0) res[i] = 1;
            //判断该点的周围8点是否有灯打开,执行关灯操作 3*3数组
            for(int x = row - 1; x <= row + 1; x++){
                for(int y = column - 1; y <= column + 1; y++){
                    //越界判断,注意点在最外面一圈的情况
                    if(x < 0 || y < 0 || x >= n || y >= n) continue;
                    //如果set中该点是开着的,移除,将该点所在行、列、两条对角线的值都减1
                    if(points.remove(x + "+" + y)){
                        //行
                        rows.put(x,rows.get(x) - 1);
                        if(rows.get(x) == 0) rows.remove(x); //如果灯亮的次数清为0了,直接从map中移除
                        //列
                        columns.put(y,columns.get(y) - 1);
                        if(columns.get(y) == 0) columns.remove(y); 
                        //正对角线
                        diagonal.put(x-y,diagonal.get(x-y) - 1);
                        if(diagonal.get(x-y) == 0) diagonal.remove(x-y); 
                        //反对角线
                        antiDiagonal.put(x+y,antiDiagonal.get(x+y) - 1);
                        if(antiDiagonal.get(x+y) == 0) antiDiagonal.remove(x+y);
                    }
                    //完成hashmap和set的更新,进行下一个坐标的判断
                }
            }
        }
        return res;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 总结

  • 分析出几种情况,然后分别对各个情况实现
微信 支付宝
#Java
最近更新
01
1686. 石子游戏VI Java
08-18
02
1688. 比赛中的配对次数 Java
08-18
03
1687. 从仓库到码头运输箱子 Java
08-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 JavaInterview.cn
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式