题目
给你一个由 '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.lengthn == grid[i].length1 <= m, n <= 300grid[i][j]的值为'0'或'1'
思路
一道很经典的图遍历算法题,可以使用BFS或DFS,思路如下:
- 1、遍历到(i,j)时,当grid[i][j]=='1';
- 2、将grid[i][j]设置为0,避免后续重复计算;
- 3、需要去查看(i+1, j)、(i-1, j)、(i, j-1)、(i, j+1)四个位置,继续对每个位置判断继续遍历...
解法一: DFS
代码一: DFS
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
def dfs(grid, i, j):
grid[i][j] = '0'
if i-1 >= 0 and grid[i-1][j] == '1':
dfs(grid, i-1, j)
if i+1 < len(grid) and grid[i+1][j] == '1':
dfs(grid, i+1, j)
if j-1 >= 0 and grid[i][j-1] == '1':
dfs(grid, i, j-1)
if j+1 < len(grid[0]) and grid[i][j+1] == '1':
dfs(grid, i, j+1)
res = 0
nr = len(grid)
nc = len(grid[0])
for i in range(nr):
for j in range(nc):
if grid[i][j] == "1":
res += 1
dfs(grid, i, j)
return res
解法二: BFS
代码二: BFS+collections.deque
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
nr = len(grid)
if nr == 0:
return 0
nc = len(grid[0])
num_islands = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
num_islands += 1
grid[r][c] = "0"
neighbors = collections.deque([(r, c)])
while neighbors:
row, col = neighbors.popleft()
for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
neighbors.append((x, y))
grid[x][y] = "0"
return num_islands
解法三: 并查集
并查集中维护连通分量的个数,在遍历的过程中:
- 初始化parents数组,为 nr * nc长度的数组,二维位置(i,j)转换为数组中
nc*i+j位置; - 相邻的陆地(只需要向右看和向下看)合并,只要发生过合并,岛屿的数量就减少 1;
- 遍历所有数组,满足条件合并,得到最后结果。
代码三: 并查集
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
nr, nc = len(grid), len(grid[0])
if nr == 0:
return 0
uf = UnionFind(grid)
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
grid[r][c] = '0'
for x, y in [(r+1, c), (r, c+1)]:
if x >= 0 and x < nr and y >= 0 and y < nc and grid[x][y] == "1":
uf.union(r * nc + c, x * nc + y)
return uf.count
class UnionFind:
def __init__(self, grid):
nr, nc = len(grid), len(grid[0])
self.count = 0
self.parent = [-1] * (nr * nc)
self.size = [0] * (nr * nc)
for r in range(nr):
for c in range(nc):
if grid[r][c] == '1':
# 初始化parent数组
self.parent[r * nc + c] = r * nc + c
# 初始化节点的大小数组
self.size[r * nc + c] = 1
self.count += 1
def find(self, x):
if self.parent[x] != x:
return self.find(self.parent[x])
return x
def union(self, x, y):
rootx, rooty = self.find(x), self.find(y)
if rootx != rooty:
# 将小的节点挂载在大的节点上
if self.size[rootx] >= self.size[rooty]:
self.parent[rooty] = self.parent[rootx]
self.size[rootx] += self.size[rooty]
else:
self.parent[rootx] = self.parent[rooty]
self.size[rooty] += self.size[rootx]
self.count -= 1