LeetCode 封闭岛屿数量问题详解:从DFS到DSU的四种解法
leetcode Leetcode solutions 项目地址: https://gitcode.com/gh_mirrors/leetcode1/leetcode
问题描述
给定一个由0(陆地)和1(水域)组成的二维网格,计算其中"封闭岛屿"的数量。封闭岛屿是指完全由水域包围的陆地区域,即岛屿的所有边界都不能接触网格的边缘。
解法一:深度优先搜索(DFS-I)
核心思路
使用DFS遍历每个陆地单元格,同时检查该陆地是否能够延伸到网格边界。如果不能延伸到边界,则说明这是一个封闭岛屿。
代码实现
class Solution:
def closedIsland(self, grid: List[List[int]]) -> int:
ROWS, COLS = len(grid), len(grid[0])
directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
visit = set()
def dfs(r, c):
if r < 0 or c < 0 or r == ROWS or c == COLS:
return 0 # 到达边界,不是封闭岛屿
if grid[r][c] == 1 or (r, c) in visit:
return 1 # 是水域或已访问过
visit.add((r, c))
res = True
for dx, dy in directions:
if not dfs(r + dx, c + dy):
res = False
return res
res = 0
for r in range(ROWS):
for c in range(COLS):
if not grid[r][c] and (r, c) not in visit:
res += dfs(r, c)
return res
复杂度分析
- 时间复杂度:O(m×n),每个单元格最多被访问一次
- 空间复杂度:O(m×n),用于存储访问记录
解法二:深度优先搜索(DFS-II)
核心思路
先处理所有边缘陆地,将它们标记为水域,然后统计剩余陆地区域的数量。
代码实现
class Solution:
def closedIsland(self, grid: list[list[int]]) -> int:
ROWS, COLS = len(grid), len(grid[0])
directions = [0, 1, 0, -1, 0]
def dfs(r, c):
if r < 0 or c < 0 or r == ROWS or c == COLS or grid[r][c] == 1:
return
grid[r][c] = 1
for d in range(4):
dfs(r + directions[d], c + directions[d + 1])
# 先处理边缘陆地
for r in range(ROWS):
dfs(r, 0)
dfs(r, COLS - 1)
for c in range(COLS):
dfs(0, c)
dfs(ROWS - 1, c)
# 统计内部岛屿
res = 0
for r in range(1, ROWS - 1):
for c in range(1, COLS - 1):
if grid[r][c] == 0:
dfs(r, c)
res += 1
return res
复杂度分析
- 时间复杂度:O(m×n)
- 空间复杂度:O(m×n),递归栈空间
解法三:广度优先搜索(BFS)
核心思路
使用BFS替代DFS来遍历陆地,同样检查是否能到达边界。
代码实现
from collections import deque
class Solution:
def closedIsland(self, grid: list[list[int]]) -> int:
ROWS, COLS = len(grid), len(grid[0])
directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]
visit = set()
res = 0
def bfs(r, c):
q = deque([(r, c)])
visit.add((r, c))
is_closed = True
while q:
x, y = q.popleft()
for dx, dy in directions:
nx, ny = x + dx, y + dy
if nx < 0 or ny < 0 or nx >= ROWS or ny >= COLS:
is_closed = False
continue
if grid[nx][ny] == 1 or (nx, ny) in visit:
continue
visit.add((nx, ny))
q.append((nx, ny))
return is_closed
for r in range(ROWS):
for c in range(COLS):
if grid[r][c] == 0 and (r, c) not in visit:
res += bfs(r, c)
return res
复杂度分析
- 时间复杂度:O(m×n)
- 空间复杂度:O(m×n),用于队列和访问记录
解法四:并查集(DSU)
核心思路
使用并查集数据结构来管理陆地的连通性,特别处理与边界相连的陆地。
代码实现
class DSU:
def __init__(self, n):
self.Parent = list(range(n + 1))
self.Size = [1] * (n + 1)
def find(self, node):
if self.Parent[node] != node:
self.Parent[node] = self.find(self.Parent[node])
return self.Parent[node]
def union(self, u, v):
pu, pv = self.find(u), self.find(v)
if pu == pv:
return False
if self.Size[pu] >= self.Size[pv]:
self.Size[pu] += self.Size[pv]
self.Parent[pv] = pu
else:
self.Size[pv] += self.Size[pu]
self.Parent[pu] = pv
return True
class Solution:
def closedIsland(self, grid: List[List[int]]) -> int:
ROWS, COLS = len(grid), len(grid[0])
N = ROWS * COLS
def index(r, c):
return r * COLS + c
dsu = DSU(N)
directions = [0, 1, 0, -1, 0]
# 处理边界和连通区域
for r in range(ROWS):
for c in range(COLS):
if grid[r][c] == 0:
for d in range(4):
nr, nc = r + directions[d], c + directions[d + 1]
if min(nr, nc) < 0 or nr == ROWS or nc == COLS:
dsu.union(N, index(r, c))
elif grid[nr][nc] == 0:
dsu.union(index(r, c), index(nr, nc))
# 统计封闭岛屿
res = 0
rootN = dsu.find(N)
for r in range(ROWS):
for c in range(COLS):
if grid[r][c] == 1:
continue
node = index(r, c)
root = dsu.find(node)
if root == node and root != rootN:
res += 1
return res
复杂度分析
- 时间复杂度:O(m×n×α(m×n)),其中α是反阿克曼函数
- 空间复杂度:O(m×n),用于存储并查集结构
总结
- DFS-I:直观易懂,适合初学者理解问题本质
- DFS-II:预处理边界,简化后续判断,代码更简洁
- BFS:适合处理大规模网格,避免递归栈溢出
- DSU:适合需要频繁查询连通性的场景,扩展性强
选择哪种方法取决于具体场景和个人偏好。对于面试和日常编程,掌握DFS和BFS两种方法即可应对大多数岛屿类问题。
leetcode Leetcode solutions 项目地址: https://gitcode.com/gh_mirrors/leetcode1/leetcode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考