Count Unguarded Cells in the Grid
MedPrompt
You are given two integers m and n representing a 0-indexed m x n grid. You are also given two 2D integer arrays guards and walls where guards[i] = [rowi, coli] and walls[j] = [rowj, colj] represent the positions of the ith guard and jth wall respectively.
A guard can see every cell in the four cardinal directions (north, east, south, or west) starting from their position unless obstructed by a wall or another guard. A cell is guarded if there is at least one guard that can see it.
Return the number of unoccupied cells that are not guarded.
Example 1:
Input: m = 4, n = 6, guards = [[0,0],[1,1],[2,3]], walls = [[0,1],[2,2],[1,4]]
Output: 7
Explanation: The guarded and unguarded cells are shown in red and green respectively in the above diagram.
There are a total of 7 unguarded cells, so we return 7.Example 2:
Input: m = 3, n = 3, guards = [[1,1]], walls = [[0,1],[1,0],[2,1],[1,2]]
Output: 4
Explanation: The unguarded cells are shown in green in the above diagram.
There are a total of 4 unguarded cells, so we return 4.
Constraints:
1 <= m, n <= 1052 <= m * n <= 1051 <= guards.length, walls.length <= 5 * 1042 <= guards.length + walls.length <= m * nguards[i].length == walls[j].length == 20 <= rowi, rowj < m0 <= coli, colj < n- All the positions in
guardsandwallsare unique.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. We use a 2D grid to represent the area, with different integer values denoting whether a cell is empty, contains a wall, a guard, or is guarded. For each guard, we trace its line of sight in the four cardinal directions, marking empty cells as guarded until an obstruction (a wall, another guard) or the edge of the grid is reached.
Algorithm
- Create an
m x ngrid and initialize all cells to0(representing empty). - Mark the positions of walls with
2and guards with1. - Iterate through each guard's position
(gr, gc). - For each guard, simulate its line of sight in all four cardinal directions (north, east, south, west).
- Trace a path from the guard's position outwards. If a cell is empty (
0), mark it as guarded (3). - Stop tracing in a direction if a wall (
2), another guard (1), or the grid boundary is encountered. - After simulating for all guards, iterate through the entire grid and count the number of cells that are still
0. - This count is the number of unguarded, unoccupied cells.
Walkthrough
We begin by setting up an m x n integer matrix, let's call it grid, initialized to all zeros. A 0 signifies an empty, currently unguarded cell.
Next, we populate this grid with the given walls and guards. We can use a simple convention: 1 for a guard and 2 for a wall. These values are placed at their respective coordinates in the grid.
The core of this method is to iterate through each guard. For each guard at (r, c), we perform four simulations, one for each direction:
- Eastward: We loop from column
c + 1ton - 1in the same rowr. - Westward: We loop from
c - 1down to0in rowr. - Southward: We loop from row
r + 1tom - 1in the same columnc. - Northward: We loop from
r - 1down to0in columnc.
During each of these traversals, we check the state of the cell. If we encounter a cell that is already a guard (1) or a wall (2), the line of sight is blocked, so we stop the traversal in that direction (break). If we find an empty cell (0), we update its state to 3 to mark it as guarded.
After completing this process for all guards, the grid accurately reflects the state of every cell. The final step is to count the number of cells that remain 0. This count gives us the total number of unoccupied and unguarded cells.
class Solution { public int countUnguarded(int m, int n, int[][] guards, int[][] walls) { // 0: empty, 1: guard, 2: wall, 3: guarded int[][] grid = new int[m][n]; for (int[] wall : walls) { grid[wall[0]][wall[1]] = 2; } for (int[] guard : guards) { grid[guard[0]][guard[1]] = 1; } for (int[] guard : guards) { int r = guard[0]; int c = guard[1]; // Look right for (int j = c + 1; j < n; j++) { if (grid[r][j] == 1 || grid[r][j] == 2) break; if (grid[r][j] == 0) grid[r][j] = 3; } // Look left for (int j = c - 1; j >= 0; j--) { if (grid[r][j] == 1 || grid[r][j] == 2) break; if (grid[r][j] == 0) grid[r][j] = 3; } // Look down for (int i = r + 1; i < m; i++) { if (grid[i][c] == 1 || grid[i][c] == 2) break; if (grid[i][c] == 0) grid[i][c] = 3; } // Look up for (int i = r - 1; i >= 0; i--) { if (grid[i][c] == 1 || grid[i][c] == 2) break; if (grid[i][c] == 0) grid[i][c] = 3; } } int unguardedCount = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (grid[i][j] == 0) { unguardedCount++; } } } return unguardedCount; }}Complexity
Time
O(G * (m + n) + m * n), where `G` is the number of guards. The `m*n` term is for grid initialization and final counting. The main cost is from simulating each guard's sight across rows and columns. This can be slow if `G`, `m`, or `n` are large.
Space
O(m * n) to store the state of each cell in the grid.
Trade-offs
Pros
The logic is straightforward and easy to implement as it directly follows the problem's description.
It's a good starting point for understanding the problem dynamics.
Cons
Can be inefficient and may result in a 'Time Limit Exceeded' error for certain test cases, especially those with a large grid dimension (
morn) and many guards.Involves redundant computations as the same cell might be checked multiple times by different guards.
Solutions
Solution
class Solution {public int countUnguarded(int m, int n, int[][] guards, int[][] walls) { int[][] g = new int[m][n]; for (var e : guards) { g[e[0]][e[1]] = 2; } for (var e : walls) { g[e[0]][e[1]] = 2; } int[] dirs = {-1, 0, 1, 0, -1}; for (var e : guards) { for (int k = 0; k < 4; ++k) { int x = e[0], y = e[1]; int a = dirs[k], b = dirs[k + 1]; while (x + a >= 0 && x + a < m && y + b >= 0 && y + b < n && g[x + a][y + b] < 2) { x += a; y += b; g[x][y] = 1; } } } int ans = 0; for (var row : g) { for (int v : row) { if (v == 0) { ++ans; } } } return ans; }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.