LeetCode 200-岛屿数量

108 阅读3分钟

题目

给你一个由 '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'

思路

一道很经典的图遍历算法题,可以使用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