Problem
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.
Examples
Example 1:
$$ \begin{bmatrix} \colorbox{blue} 0 & \colorbox{orange} 1 & \colorbox{orange} 1 & \colorbox{blue} 0 \\ \colorbox{blue} 0 & \colorbox{orange} 1 & \colorbox{orange} 1 & \colorbox{blue} 0 \\ \colorbox{blue} 0 & \colorbox{blue} 0 & \colorbox{blue} 0 & \colorbox{blue} 0 \end{bmatrix} \Longrightarrow \begin{bmatrix} \colorbox{blue} 0 & \colorbox{orange} 1 & \colorbox{darkblue} 0 & \colorbox{blue} 0 \\ \colorbox{blue} 0 & \colorbox{darkblue} 0 & \colorbox{orange} 1 & \colorbox{blue} 0 \\ \colorbox{blue} 0 & \colorbox{blue} 0 & \colorbox{blue} 0 & \colorbox{blue} 0 \end{bmatrix} $$
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:
$$ \begin{bmatrix} \colorbox{orange} 1 & \colorbox{orange} 1 \end{bmatrix} \Longrightarrow \begin{bmatrix} \colorbox{navy} 0 & \colorbox{navy} 0 \end{bmatrix} $$
Input:
grid =[[1,1]]
Output:
2
Explanation: Grid of full water is also disconnected ([[1,1]] -> [[0,0]]), 0 islands.
Solution
This problem can be approached using graph traversal techniques such as Depth-First Search (DFS) or Breadth-First Search (BFS).
Method 1 - DFS
The key idea behind this problem is that answer is always less than equal to 2.
Why?
Consider the 3x3 grid island filled with the land (all 1s):
1 1 1
1 1 1
1 1 1
Now, lets focus on the center cell, and we chop of 2 edges connected to it, i.e. we sink 2 adjacent islands:
1 1 1
1 X 0
1 0 1
Now, the island is not connected. Read more about it here: https://en.wikipedia.org/wiki/Biconnected_component.
Steps
Here the cases we can handle:
- Check if the grid is already disconnected: If the grid has no land or more than one island, it is already disconnected, hence return 0.
- Check if removing one land cell will disconnect the grid immediately: Iterate through each land cell, temporarily remove it, and check the connectivity of the grid. If removing any single land cell results in more than one island, return 1.
- If not, return 2: If the above conditions are not met, then the minimum number of days required to disconnect the grid will be 2 under all other circumstances.
Video Explanation
Here is the video explaining above algorithm in detail:
Code
Java
public class Solution {
private static final int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public int minDays(int[][] grid) {
if (!isConnected(grid)) {
return 0;
}
int m = grid.length;
int n = grid[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
grid[i][j] = 0; // Temporarily remove the land
if (!isConnected(grid)) {
return 1;
}
grid[i][j] = 1; // Restore the land
}
}
}
return 2;
}
private boolean isConnected(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[] start = findStart(grid);
if (start == null) {
return false; // No land found
}
boolean[][] visited = new boolean[m][n];
// try to visit whole island from starting point
dfs(grid, visited, start[0], start[1]);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// if some cell is unvisited, island is disconnected
if (grid[i][j] == 1 && !visited[i][j]) {
return false;
}
}
}
return true;
}
private int[] findStart(int[][] grid) {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
return new int[]{i, j};
}
}
}
return null;
}
private void dfs(int[][] grid, boolean[][] visited, int r, int c) {
if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length || visited[r][c] || grid[r][c] == 0) {
return;
}
visited[r][c] = true;
for (int i = 0; i < 4; i++) {
int newR = r + DIRS[i][0];
int newC = c + DIRS[i][1];
dfs(grid, visited, newR, newC);
}
}
}
Python
def minDays(grid):
def is_connected(grid):
rows, cols = len(grid), len(grid[0])
visited = [[False] * cols for _ in range(rows)]
def dfs(x, y):
if (
x < 0
or x >= rows
or y < 0
or y >= cols
or visited[x][y]
or grid[x][y] == 0
):
return
visited[x][y] = True
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
dfs(x + dx, y + dy)
# Find the first land cell and start DFS from there
start = None
for i in range(rows):
for j in range(cols):
if grid[i][j] == 1:
start = (i, j)
break
if start:
break
if not start:
return False # No land found
dfs(start[0], start[1])
for i in range(rows):
for j in range(cols):
if grid[i][j] == 1 and not visited[i][j]:
return False # Found unvisited land meaning disconnected
return True
# Initial check if already disconnected
if not is_connected(grid):
return 0
# Try to disconnect by removing one land cell
rows, cols = len(grid), len(grid[0])
for i in range(rows):
for j in range(cols):
if grid[i][j] == 1:
grid[i][j] = 0
if not is_connected(grid):
return 1
grid[i][j] = 1 # Restore the land cell
# If can't be disconnected by removing one cell, return 2
return 2
Complexity
- ⏰ Time complexity:
O(m*n) ^ 2
isConnected
takesO(m*n)
time, it also calls DFS to determine connectivity.- Trying to sink 1 cell at a time, takes
O(m*n)
time, and for that we are callingisConnected
function each time, so it takesO(m*n)^2
time
- 🧺 Space complexity:
O(m*n)
, for using auxiliary visited set.