200. 岛屿数量 BFS+DFS+并查集(Python 3)
给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
本题根本是求连通域个数
- 循环实现广度优先BFS(使用队列):
from collections import deque
class Solution:
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
def numIslands(self, grid: List[List[str]]) -> int:
m = len(grid) #行
if m == 0:
return 0
n = len(grid[0]) # 列
marked = [[False for i in range(n)] for i in range(m)]
count = 0
for i in range(m):
for j in range(n):
if not marked[i][j] and grid[i][j] == '1':
queue = deque()
count += 1
queue.append((i,j))
marked[i][j] = True
while queue:
cur_x, cur_y = queue.popleft() # key step
for direction in self.directions:
new_i = cur_x + direction[0]
new_j = cur_y + direction[1]
if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1':
queue.append((new_i, new_j))
marked[new_i][new_j] = True
return count
- 循环实现深度优先DFS(使用栈):
class Solution:
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
def numIslands(self, grid: List[List[str]]) -> int:
count = 0
m = len(grid)
if m == 0:
return 0
n = len(grid[0])
marked = [[False for i in range(n)] for i in range(m)]
for i in range(m):
for j in range(n):
if not marked[i][j] and grid[i][j] == '1':
stack = []
stack.append((i, j))
marked[i][j] = True
count += 1
while stack:
cur_i, cur_j = stack.pop()
for direction in self.directions:
new_i = cur_i + direction[0]
new_j = cur_j + direction[1]
if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1':
stack.append((new_i, new_j))
marked[new_i][new_j] = True
return count
- 递归实现DFS方法:
class Solution:
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
def find(self, grid: List[List[str]], i, j):
if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] != '1':
return
grid[i][j] = '2'
for direction in self.directions:
self.find(grid, i + direction[0], j + direction[1])
def numIslands(self, grid: List[List[str]]) -> int:
count = 0
m = len(grid)
if m == 0:
return 0
n = len(grid[0])
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
self.find(grid, i, j)
count += 1
return count
- 并查集,只考虑向右和向下两个方向,而不是四个方向
from typing import List
class Solution:
# 并查集
def numIslands(self, grid: List[List[str]]) -> int:
# 每个节点表示集合的一个元素,每个元素用一个数字表示
class UnionFind:
def __init__(self, n: int):
self.count = n
self.parent = [i for i in range(n)] # 每个元素的树根,开始时为自身
self.rank = [1 for _ in range(n)] # 每个节点的初始秩
def getCount(self) -> int:
return self.count
def find(self,p): # 递归寻找树根
if(p != self.parent[p]):
self.parent[p] = self.find(self.parent[p])
return self.parent[p]
def union(self, p, q): # 按秩合并,将具有较小秩的树根指向具有较大秩的树根
p_root = self.find(p)
q_root = self.find(q)
if p_root == q_root:
return
if self.rank[p_root] > self.rank[q_root]:
self.parent[q_root] = p_root
self.rank[p_root] += 1
else:
self.parent[p_root] = q_root
self.rank[q_root] += 1
self.count -= 1
m = len(grid)
if m == 0:
return 0
n = len(grid[0])
def getIndex(x, y):
return x * n + y
uf = UnionFind(m * n)
water = 0
for i in range(m):
for j in range(n):
if grid[i][j] == '0':
water += 1
else:
if i + 1 < m and grid[i + 1][j] == '1':
uf.union(getIndex(i, j), getIndex(i + 1, j))
if j + 1 < n and grid[i][j + 1] == '1':
uf.union(getIndex(i, j), getIndex(i, j + 1))
return uf.getCount() - water