统计网格图中没有被保卫的格子数
难度:
标签:
题目描述
给你两个整数 m
和 n
表示一个下标从 0 开始的 m x n
网格图。同时给你两个二维整数数组 guards
和 walls
,其中 guards[i] = [rowi, coli]
且 walls[j] = [rowj, colj]
,分别表示第 i
个警卫和第 j
座墙所在的位置。
一个警卫能看到 4 个坐标轴方向(即东、南、西、北)的 所有 格子,除非他们被一座墙或者另外一个警卫 挡住 了视线。如果一个格子能被 至少 一个警卫看到,那么我们说这个格子被 保卫 了。
请你返回空格子中,有多少个格子是 没被保卫 的。
示例 1:
输入:m = 4, n = 6, guards = [[0,0],[1,1],[2,3]], walls = [[0,1],[2,2],[1,4]] 输出:7 解释:上图中,被保卫和没有被保卫的格子分别用红色和绿色表示。 总共有 7 个没有被保卫的格子,所以我们返回 7 。
示例 2:
输入:m = 3, n = 3, guards = [[1,1]], walls = [[0,1],[1,0],[2,1],[1,2]] 输出:4 解释:上图中,没有被保卫的格子用绿色表示。 总共有 4 个没有被保卫的格子,所以我们返回 4 。
提示:
1 <= m, n <= 105
2 <= m * n <= 105
1 <= guards.length, walls.length <= 5 * 104
2 <= guards.length + walls.length <= m * n
guards[i].length == walls[j].length == 2
0 <= rowi, rowj < m
0 <= coli, colj < n
guards
和walls
中所有位置 互不相同 。
代码结果
运行时间: 274 ms, 内存: 36.6 MB
/*
* 思路:
* 使用Java Stream API实现同样的逻辑:
* 1. 创建一个m x n的二维数组grid,初始化为0表示空格子。
* 2. 将guards和walls的位置在grid中标记为2和1,表示警卫和墙。
* 3. 对于每个警卫,向四个方向遍历,直到遇到墙或另一个警卫,将路径上的格子标记为3,表示被保卫。
* 4. 遍历整个grid,统计没有被保卫的格子数量(值为0的格子)。
*/
import java.util.Arrays;
import java.util.stream.IntStream;
public class Solution {
public int countUnguarded(int m, int n, int[][] guards, int[][] walls) {
int[][] grid = new int[m][n];
Arrays.stream(walls).forEach(wall -> grid[wall[0]][wall[1]] = 1); // 标记墙
Arrays.stream(guards).forEach(guard -> grid[guard[0]][guard[1]] = 2); // 标记警卫
Arrays.stream(guards).forEach(guard -> markGuarded(grid, guard[0], guard[1], m, n));
return (int) IntStream.range(0, m).flatMap(i -> IntStream.range(0, n).filter(j -> grid[i][j] == 0)).count(); // 统计未被保卫的格子数量
}
private void markGuarded(int[][] grid, int x, int y, int m, int n) {
int[] dx = {0, 0, 1, -1};
int[] dy = {1, -1, 0, 0};
for (int d = 0; d < 4; d++) {
int nx = x + dx[d];
int ny = y + dy[d];
while (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] != 1 && grid[nx][ny] != 2) {
if (grid[nx][ny] == 0) {
grid[nx][ny] = 3; // 标记为被保卫
}
nx += dx[d];
ny += dy[d];
}
}
}
}
解释
方法:
这道题目要求统计一个网格中未被警卫保护的格子数量。题解中采用了模拟的方式:首先,使用一个二维数组表示整个网格,初始化为0。将警卫和墙的位置分别标记为-1(警卫)和-2(墙)。然后,从每一个警卫的位置出发,向四个方向(北、南、西、东)扩展,标记所有这些警卫可以看到的格子为1,代表这些格子被保护了。此扩展在遇到另一个警卫或墙时停止。最后,计算所有未被保护的格子的数量,即网格总数减去被保护的格子数、警卫数和墙的数目。
时间复杂度:
O((guards.length * (m + n)) + m * n)
空间复杂度:
O(m * n)
代码细节讲解
🦆
在处理警卫视线扩展时,为什么没有考虑通过其他警卫的格子继续扩展视线?
▷🦆
题解中提到'此扩展在遇到另一个警卫或墙时停止',这个逻辑是基于什么考虑?是否有可能某些被其他警卫看到的格子因此没有被正确标记?
▷🦆
题解中的算法对于网格的每个方向单独进行了扩展,这种方法是否最优?是否有可能通过更高效的方式(例如使用队列)来优化视线的扩展过程?
▷🦆
在计算未被保卫的格子数量时,是否考虑了某些格子可能同时被多个警卫保护,而计数时重复减去这些格子?
▷