这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战
难度:中等
题目描述
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [ ["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2:
输入:grid = [ ["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'
解题思路
深搜 + 广搜 + 并查集
-
深度优先搜索: 求连通块的个数
- 每次深度搜索可以遍历图中的一个连通块,所以,深度搜索的次数就是连通块的个数
- 每访问一个为"1"的位置,将其替换为"0",代替 visd 数组标记节点是否被访问过
-
深度优先搜索
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
# 深度优先搜索:
def dfs(i, j):
grid[i][j] = '0'
for x, y in [(i+1, j), (i-1, j), (i, j+1), (i, j-1)]:
if x>=0 and x<n and y>=0 and y<m and grid[x][y]=='1':
dfs(x, y)
n, m = len(grid), len(grid[0])
res = 0
for i in range(n):
for j in range(m):
# 深搜的次数就是岛屿的个数
if grid[i][j] == '1':
res += 1
dfs(i, j)
return res
- 广度优先搜索
- 使用广度优先搜索,搜索的次数就是连通块的个数,即岛屿的数量
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
# 深度优先搜索:
def bfs(i, j):
queue = [(i, j)]
grid[i][j] = "0"
while queue:
x, y = queue.pop(0)
for a, b in [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]:
if a>=0 and a<n and b>=0 and b<m and grid[a][b]=="1":
queue.append((a, b))
grid[a][b] = "0"
n, m = len(grid), len(grid[0])
res = 0
for i in range(n):
for j in range(m):
if grid[i][j] == "1":
res += 1
bfs(i, j)
return res
- 并查集
- 初始化每个位置为一个集合,用i*col+j唯一标识每个元素
- 初始化size=col*row
- 合并连通的元素为一个集合,每合并一次,size-1
- 最终size = 连通块的个数 + 水的元素个数
- 故在遍历每个元素的时候,统计水的个数
- 岛屿数量 = size - 水的个数
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
# 岛屿数量 = (总元素个数 - 水的个数)中的连通块的个数
class unionFind:
def __init__(self, n):
# 总数
self.size = n
self.p = [i for i in range(n)]
def find(self, x):
# 查找根节点,即当前元素所属的集合
if self.p[x] != x:
self.p[x] = self.find(self.p[x])
return self.p[x]
def union(self, a, b):
ar, br = self.find(a), self.find(b)
# 两个元素位于同一个集合,跳过
if ar == br:
return
# 不在同一个集合,合并
else:
self.p[ar] = br
self.size -= 1
n, m = len(grid), len(grid[0])
ocean = 0 # 统计水的个数
uf = unionFind(n*m)
for i in range(n):
for j in range(m):
# 统计水的个数
if grid[i][j] == "0":
ocean += 1
else:
# 只需向右和向下查看
if i+1 < n and grid[i+1][j]=="1":
uf.union(i*m+j, (i+1)*m+j)
if j+1 < m and grid[i][j+1]=="1":
uf.union(i*m+j, i*m+(j+1))
return uf.size - ocean