题目
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
思路
遍历所有位置,每个位置利用DFS去扫描岛屿边界。
class Solution:def numIslands(self, grid: List[List[str]]) -> int:if not grid or len(grid) == 0: return 0rows, cols = len(grid), len(grid[0])count = 0for row in range(rows):for col in range(cols):if grid[row][col] == '1':count += 1self.dfs(grid, row, col)return countdef dfs(self, grid, row, col):if row < 0 or row >= len(grid) or col < 0 or col >= len(grid[0]) or grid[row][col] != '1':returnelse:grid[row][col] = '2' # 用'2'标记已经访问的位置# 探索上下左右四个方向self.dfs(grid, row - 1, col) # 上self.dfs(grid, row + 1, col) # 下self.dfs(grid, row, col - 1) # 左self.dfs(grid, row, col + 1) # 右
深度优先搜索
from typing import Listclass Solution:# x-1,y# x,y-1 x,y x,y+1# x+1,y# 方向数组,它表示了相对于当前位置的 4 个方向的横、纵坐标的偏移量,这是一个常见的技巧directions = [(-1, 0), (0, -1), (1, 0), (0, 1)]def numIslands(self, grid: List[List[str]]) -> int:m = len(grid)# 特判if m == 0:return 0n = len(grid[0])marked = [[False for _ in range(n)] for _ in range(m)]count = 0# 从第 1 行、第 1 格开始,对每一格尝试进行一次 DFS 操作for i in range(m):for j in range(n):# 只要是陆地,且没有被访问过的,就可以使用 DFS 发现与之相连的陆地,并进行标记if not marked[i][j] and grid[i][j] == '1':# count 可以理解为连通分量,你可以在深度优先遍历完成以后,再计数,self.__dfs(grid, i, j, m, n, marked)count += 1return countdef __dfs(self, grid, i, j, m, n, marked):marked[i][j] = Truefor direction in self.directions:new_i = i + direction[0]new_j = 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':self.__dfs(grid, new_i, new_j, m, n, marked)if __name__ == '__main__':grid = [['1', '1', '1', '1', '0'],['1', '1', '0', '1', '0'],['1', '1', '0', '0', '0'],['0', '0', '0', '0', '0']]solution = Solution()result = solution.numIslands(grid)print(result)
广度优先搜索
为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 11,则将其加入队列,开始进行广度优先搜索。
from typing import Listfrom collections import dequeclass Solution:# x-1,y# x,y-1 x,y x,y+1# x+1,y# 方向数组,它表示了相对于当前位置的 4 个方向的横、纵坐标的偏移量,这是一个常见的技巧directions = [(-1, 0), (0, -1), (1, 0), (0, 1)]def numIslands(self, grid: List[List[str]]) -> int:m = len(grid)# 特判if m == 0:return 0n = len(grid[0])marked = [[False for _ in range(n)] for _ in range(m)]count = 0# 从第 1 行、第 1 格开始,对每一格尝试进行一次 DFS 操作for i in range(m):for j in range(n):# 只要是陆地,且没有被访问过的,就可以使用 BFS 发现与之相连的陆地,并进行标记if not marked[i][j] and grid[i][j] == '1':# count 可以理解为连通分量,你可以在广度优先遍历完成以后,再计数,# 即这行代码放在【位置 1】也是可以的count += 1queue = deque()queue.append((i, j))# 注意:这里要标记上已经访问过marked[i][j] = Truewhile queue:cur_x, cur_y = queue.popleft()# 得到 4 个方向的坐标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#【位置 1】return countif __name__ == '__main__':grid = [['1', '1', '1', '1', '0'],['1', '1', '0', '1', '0'],['1', '1', '0', '0', '0'],['0', '0', '0', '0', '0']]solution = Solution()result = solution.numIslands(grid)print(result)作者:liweiwei1419链接:https://leetcode-cn.com/problems/number-of-islands/solution/dfs-bfs-bing-cha-ji-python-dai-ma-java-dai-ma-by-l/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
