You are given an m x n binary grid grid where 1 represents land and 0 represents water. An island is a maximal 4-directionally (horizontal or vertical) connected group of 1's.
The grid is said to be connected if we have exactly one island, otherwise is said disconnected.
In one day, we are allowed to change any single land cell (1) into a water cell (0).
Return the minimum number of days to disconnect the grid.
Example 1:
Input: grid = [[0,1,1,0],[0,1,1,0],[0,0,0,0]] Output: 2 Explanation: We need at least 2 days to get a disconnected grid. Change land grid[1][1] and grid[0][2] to water and get 2 disconnected island.
Example 2:
Input: grid = [[1,1]] Output: 2 Explanation: Grid of full water is also disconnected ([[1,1]] -> [[0,0]]), 0 islands.
Constraints:
m == grid.lengthn == grid[i].length1 <= m, n <= 30grid[i][j] is either 0 or 1.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy involves checking every possible action we can take to disconnect the island. We try removing each land cell, one at a time, and see if that disconnects the island. If not, we try removing pairs of land cells, one at a time, to see if that disconnects the island.
Here's how the algorithm would work step-by-step:
def min_days_to_disconnect(grid):
rows = len(grid)
cols = len(grid[0])
def count_islands(current_grid):
visited = set()
island_count = 0
def dfs(row, col):
if (row < 0 or row >= rows or col < 0 or col >= cols or
(row, col) in visited or current_grid[row][col] == 0):
return
visited.add((row, col))
dfs(row + 1, col)
dfs(row - 1, col)
dfs(row, col + 1)
dfs(row, col - 1)
for row in range(rows):
for col in range(cols):
if current_grid[row][col] == 1 and (row, col) not in visited:
dfs(row, col)
island_count += 1
return island_count
initial_islands = count_islands(grid)
if initial_islands != 1:
return 0
land_cells = []
for row in range(rows):
for col in range(cols):
if grid[row][col] == 1:
land_cells.append((row, col))
# Check removing one land cell
for row_to_remove, col_to_remove in land_cells:
temp_grid = [row[:] for row in grid]
temp_grid[row_to_remove][col_to_remove] = 0
if count_islands(temp_grid) != 1:
return 1
# Check removing two land cells
for i in range(len(land_cells)):
for j in range(i + 1, len(land_cells)):
first_row_remove, first_col_remove = land_cells[i]
second_row_remove, second_col_remove = land_cells[j]
temp_grid = [row[:] for row in grid]
temp_grid[first_row_remove][first_col_remove] = 0
temp_grid[second_row_remove][second_col_remove] = 0
if count_islands(temp_grid) != 1:
return 2
# If no single or double removal disconnects, return 2
return 2The key is to recognize that we only need to disconnect the island, not find the absolute fewest moves. Therefore, we check for edge cases first, then use a clever connectivity test to determine the minimum days needed.
Here's how the algorithm would work step-by-step:
def minimum_days_to_disconnect_island(grid):
number_of_rows = len(grid)
number_of_columns = len(grid[0])
def count_islands(current_grid):
number_of_islands = 0
visited = set()
def depth_first_search(row, column):
if (row < 0 or row >= number_of_rows or
column < 0 or column >= number_of_columns or
(row, column) in visited or current_grid[row][column] == 0):
return
visited.add((row, column))
depth_first_search(row + 1, column)
depth_first_search(row - 1, column)
depth_first_search(row, column + 1)
depth_first_search(row, column - 1)
for row in range(number_of_rows):
for column in range(number_of_columns):
if current_grid[row][column] == 1 and (row, column) not in visited:
depth_first_search(row, column)
number_of_islands += 1
return number_of_islands
number_of_land_cells = sum(sum(row) for row in grid)
# Handle edge cases with zero or one land cell
if number_of_land_cells <= 1:
return 0
# If island is already disconnected, return 0
if count_islands(grid) != 1:
return 0
# Check if removing one land cell disconnects the island
for row in range(number_of_rows):
for column in range(number_of_columns):
if grid[row][column] == 1:
temp_grid = [row[:] for row in grid]
temp_grid[row][column] = 0
# Count the number of islands after removal
if count_islands(temp_grid) != 1:
return 1
# If one removal doesn't disconnect, return 2
return 2| Case | How to Handle |
|---|---|
| Null or empty grid | Return 0 immediately, as there's no island to disconnect. |
| Grid with only one cell (1x1) | Return 1 if the cell is land (1), 0 otherwise, since removing it disconnects the (non-existent) island. |
| Grid with two cells, both representing land | Return 1, as removing either cell disconnects the island. |
| Grid represents a single connected island (no bridges needed) | Check if the island is already disconnected; if not, find articulation points and return 1 if found, or 2 if no articulation points exist. |
| Grid represents multiple disconnected islands | Return 0, since the island is already disconnected. |
| Large grid (potential stack overflow with DFS) | Use iterative DFS (stack-based) or BFS to avoid recursion depth limits. |
| Grid filled entirely with water (all 0s) | Return 0, as there's no island to disconnect. |
| Grid filled entirely with land (all 1s) | Check for articulation points; if none, return 2 (need to remove two land cells to disconnect). |