1、题目描述
给你一个由 '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、岛屿(网格)类问题dfs方法
2.1 思路
岛屿类问题可以类比二叉树的dfs方法,首先,二叉树的dfs方法如下所示:
def dfs(node) {
# 判断是否越界
if (node == null) {
return;
}
# 访问两个相邻结点
dfs(node.left);
dfs(node.right);
}
更详细的前、中、后序遍历可参考:【二叉树】遍历总结!_二叉树遍历所有路径-CSDN博客
由此,网格类问题的dfs需要首先考虑两个问题:
(1) 如何遍历相邻的格子?
对二叉树来说,对网格类问题来说,(r,c)四个相邻的格子分别是(r-1,c)、(r+1,c)、(r,c-1)和(r,c+1)。
(r-1,c) | ||
(r,c-1) | (r,c) | (r,c+1) |
(r+1,c) |
则其dfs结构可表示为:
dfs(r+1, c)
dfs(r-1, c)
dfs(r, c+1)
dfs(r, c-1)
(2)如何防止越界问题?
在二叉树中,当访问到叶子节点时,不能再继续进行遍历;在网格类问题中,网格的四边都不能出界,即表示为:
m,n = len(grid), len(grid[0])
if r<0 or c<0 or r >= m or c >= n:
return
但在网格类问题中,因为其在四周遍历的缘故,其可能会出现重复访问的情况,那么应该考虑第3个问题:
(3)如何防止重复访问?
答案是可以通过标记已经访问过的格子,从而防止重复遍历,通常将其标记为2。即:
- 0 —— 海洋格子
- 1 —— 陆地格子(未遍历过)
- 2 —— 陆地格子(已遍历过)
❗ 理论上来说可以将访问过的格子标记为除1以外的任何数,但最好不要将其标记为0,此时,无法区分海洋格子和遍历过的陆地格子,在更复杂的题目中,可能会出错。
2.2 dfs代码
综上,岛屿问题的dfs代码可总结如下:
lass Solution:
def numIslands(self, grid: List[List[str]]) -> int:
m,n = len(grid), len(grid[0])
def dfs(r,c ):
if r<0 or c<0 or r >= m or c >= n or grid[r][c]!='1':
return
grid[r][c] = '2'
dfs(r+1, c)
dfs(r-1, c)
dfs(r, c+1)
dfs(r, c-1)
#'1'或1 根据题目实际情况
所有岛屿类问题,均可根据dfs算法进行分析求解
3 本题解法
3.1 思路
岛屿是与水平/竖直相邻的陆地连接而成,陆地的格子表示为1(未遍历),因此,可对网格中每个格子进行遍历,通过访问其周边的格子,并将访问过的陆地标记为2。则当遇到一个未被访问过的陆地('1'
)时,启动 DFS 来标记所有与之相连的陆地。每次启动 DFS 时,意味着发现了一个新的岛屿,因此岛屿数量加 1。当没有‘1’格子时,表示已经不存在新岛屿。
3.2 代码
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
m,n = len(grid), len(grid[0])
def dfs(r,c ):
if r<0 or c<0 or r >= m or c >= n or grid[r][c]!='1':
return
grid[r][c] = '2'
dfs(r+1, c)
dfs(r-1, c)
dfs(r, c+1)
dfs(r, c-1)
res = 0
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
dfs(i, j)
res += 1
return res