200岛屿数量
题目:给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
来源:https://leetcode-cn.com/problems/number-of-islands/
法一:bfs 别人的代码
思路:先用一个bool数组用于记录标记过的每个位置,再依次遍历每个位置,一旦遇到一个1的区域,就把它全部遍历完,并把遍历过的记入bool数组中,本题的关键是一旦遇到一个区域就全部遍历完
from typing import List from collections import deque class 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 0 n = len(grid[0]) # 制作标记矩阵,如果遍历过该点了,标记为True,本来为False 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 += 1 queue = deque() queue.append((i, j)) # 注意:这里要标记上已经访问过 marked[i][j] = True while 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 count
法二:并查集
思路:遍历每个位置,如果当前位置为1,则向上和向左遍历两个位置,如果上面的位置为1,则以其为key,以当前位置为values进行记录,这样每个区域都有一个最高级别的values,最后把这个values提取出来,values的不同个数即为区域的个数。
from typing import List class Solution: def numIslands(self, grid: List[List[str]]) -> int: f = {} def find(x): f.setdefault(x, x) # 如果不相等,则说明之前已经将该位置进行标记为某一类了, if f[x] != x: f[x] = find(f[x]) return f[x] # y是当前为1的位置,x是向上或向左为1的位置 # 注意这个字典中,前面的key包含于后面的values,也就是说values是上级 def union(x, y): f[find(x)] = find(y) if not grid: return 0 row = len(grid) col = len(grid[0]) for i in range(row): for j in range(col): if grid[i][j] == "1": for x, y in [[-1, 0], [0, -1]]: tmp_i = i + x tmp_j = j + y if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1": union(tmp_i * col + tmp_j, i * col + j) print(f) res = set() # 这里是为了找到最上面的上级 for i in range(row): for j in range(col): if grid[i][j] == "1": res.add(find((i * col + j))) return len(res) if __name__ == '__main__': grid = [['1', '0', '1'], ['1', '0', '1'], ['0', '1', '1'],] solution = Solution() result = solution.numIslands(grid) print(result)
ttt