The grid can be considered as an undirected graph where cells are the vertices and an edge (u, v) means both cells have "1" in them and they are neighbor of each other.
DFS
Each island is a connected component (cc) in the grid graph. So, we can count the cc’s in one DFS.
Time: . If the entire grid is an island, the DFS will spiral towards the center, space:
.
from itertools import product as cartesian
class Solution:
def dfs(self, r, c, grid):
is_valid_row = lambda r: 0 <= r < len(grid)
is_valid_col = lambda c: 0 <= c < len(grid[0])
grid[r][c] = "*"
for dr, dc in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
r2, c2 = r + dr, c + dc
if not is_valid_row(r2) or not is_valid_col(c2):
continue
if grid[r2][c2] != "1":
continue
self.dfs(r2, c2, grid)
def numIslands(self, grid: List[List[str]]) -> int:
m, n = len(grid), len(grid[0])
island_count = 0
for r, c in cartesian(range(m), range(n)):
if grid[r][c] == "1":
island_count += 1
self.dfs(r, c, grid)
return island_count
BFS
Time: , space:
.
from itertools import product as cartesian
class Solution:
def bfs(self, u, grid):
is_valid_row = lambda r: 0 <= r < len(grid)
is_valid_col = lambda c: 0 <= c < len(grid[0])
q = deque([u])
while q:
r, c = q.popleft()
grid[r][c] = "*"
for dr, dc in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
r2, c2 = r+dr, c+dc
if not is_valid_row(r2) or not is_valid_col(c2):
continue
if grid[r2][c2] != "1":
continue
q.append( (r2, c2) )
def numIslands(self, grid: List[List[str]]) -> int:
island_count = 0
m, n = len(grid), len(grid[0])
for r, c in cartesian(range(m), range(n)):
if grid[r][c] != "1":
continue
island_count += 1
self.bfs((r, c), grid)
return island_count
Union-find
We start with the count of 1-cell’s number of connected components. For each 1-cell, we add at most four edges. If two of these cells were not previously connected, the number of connected components reduces by one.
Time: , space:
.
from itertools import product as cartesian
class UnionFind:
def __init__(self, grid):
m, n = len(grid), len(grid[0])
self.parent_of, self.rank_of = {}, {}
self.component_count = 0
for r, c in cartesian(range(m), range(n)):
if grid[r][c] != "1":
continue
self.parent_of[(r, c)] = (r, c)
self.rank_of[(r, c)] = 0
self.component_count += 1
def __compress_path(self, u, root):
while u != (p := self.parent_of[u]):
self.parent_of[u] = root
u = p
def __find(self, u):
root = u
while root != (p := self.parent_of[root]):
root = p
self.__compress_path(u, root)
return root
def connect(self, u, v):
root_u = self.__find(u)
root_v = self.__find(v)
if root_u == root_v:
return
self.component_count -= 1
rank_u = self.rank_of[u]
rank_v = self.rank_of[v]
if rank_u == rank_v:
self.parent_of[root_u] = root_v
self.rank_of[root_v] += 1
return
if rank_u > rank_v:
self.parent_of[root_v] = root_u
else:
self.parent_of[root_u] = root_v
class Solution:
def get_edges(self, r, c, grid):
if grid[r][c] != "1":
return []
is_valid_row = lambda r: 0 <= r < len(grid)
is_valid_col = lambda c: 0 <= c < len(grid[0])
edges = []
for dr, dc in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
r2, c2 = r + dr, c + dc
if not is_valid_row(r2) or not is_valid_col(c2):
continue
if grid[r2][c2] != "1":
continue
edges.append([(r, c), (r2, c2)])
return edges
def numIslands(self, grid: List[List[str]]) -> int:
uf = UnionFind(grid)
m, n = len(grid), len(grid[0])
for r, c in cartesian(range(m), range(n)):
for e in self.get_edges(r, c, grid):
u, v = e
uf.connect(u, v)
return uf.component_count
Leave a comment