You are given a 2D grid consisting of 0s (land) and 1s (water). An island is a maximal 4-directionally connected group of 0s, and a closed island is an island completely (all left, top, right, bottom) surrounded by 1s. Write a function to return the number of closed islands.
Example 1:
Input: grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
Output: 2
Explanation: Islands in gray are closed because they are completely surrounded by water (group of 1s).
Example 2:
Input: grid = [[0,0,1,0,0],[0,1,0,1,0],[0,1,1,1,0]]
Output: 1
Example 3:
Input: grid = [[1,1,1,1,1,1,1],
[1,0,0,0,0,0,1],
[1,0,1,1,1,0,1],
[1,0,1,0,1,0,1],
[1,0,1,1,1,0,1],
[1,0,0,0,0,0,1],
[1,1,1,1,1,1,1]]
Output: 2
Clarifications:
One straightforward approach is to iterate through each cell of the grid. If a cell is land (0), perform a Depth-First Search (DFS) or Breadth-First Search (BFS) to explore the entire island. During the exploration, check if the island touches the boundary of the grid. If it does, it's not a closed island. Count the islands that are completely surrounded by water.
def closedIsland_naive(grid):
if not grid:
return 0
rows, cols = len(grid), len(grid[0])
visited = set()
closed_islands = 0
def dfs(i, j):
if i < 0 or i >= rows or j < 0 or j >= cols or grid[i][j] == 1 or (i, j) in visited:
return True # Return True for water and visited cells
visited.add((i, j))
# Check if the current cell is on the boundary
is_boundary = (i == 0 or i == rows - 1 or j == 0 or j == cols - 1)
up = dfs(i - 1, j)
down = dfs(i + 1, j)
left = dfs(i, j - 1)
right = dfs(i, j + 1)
return not is_boundary and up and down and left and right
for i in range(rows):
for j in range(cols):
if grid[i][j] == 0 and (i, j) not in visited:
if dfs(i, j):
closed_islands += 1
return closed_islands
visited
set and the recursion stack of DFS.The optimal approach aims to reduce redundant checks by first identifying and eliminating islands that are not closed. This involves performing a DFS or BFS starting from the boundary cells. Any land connected to the boundary is, by definition, not a closed island. Mark these land cells as water (1) to effectively remove them from consideration. Then, count the remaining closed islands in the interior of the grid.
def closedIsland(grid):
if not grid:
return 0
rows, cols = len(grid), len(grid[0])
def dfs(i, j):
if i < 0 or i >= rows or j < 0 or j >= cols or grid[i][j] == 1:
return
grid[i][j] = 1 # Mark as water
dfs(i - 1, j)
dfs(i + 1, j)
dfs(i, j - 1)
dfs(i, j + 1)
# Eliminate islands connected to the boundary
for i in range(rows):
for j in range(cols):
if i == 0 or i == rows - 1 or j == 0 or j == cols - 1:
if grid[i][j] == 0:
dfs(i, j)
# Count remaining closed islands
closed_islands = 0
for i in range(rows):
for j in range(cols):
if grid[i][j] == 0:
closed_islands += 1
dfs(i, j) # Sink the island to avoid recounting
return closed_islands