[路飞]_岛屿数量

116 阅读1分钟

「这是我参与2022首次更文挑战的第30天,活动详情查看:2022首次更文挑战

leetcode-200 岛屿数量

题目介绍

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

解题思路

此题涉及连通性问题,可以使用并查集来解决。首先来思考几个关键点:

  1. 如何将利用连通性来连接两个点? 因为二维数组中的每个点都表示 陆地 或者 ,假设二维数组的行数 m = grid.length,二维数组的列数 n = grid[i].length,那么每一个点都可以用 i * n + j 来转换成数字表示,方便并查集进行连通

  2. 每个点需要判断几个方向的连通路径?

1645026899(1).png
如图,假设一块陆地的上下左右都是陆地,那么中间的陆地需要判断几个方向的连通路径?因为我们是按行按列依次进行遍历和连通,如果中间的陆地分别与上下左右四个方向进行连通,那么当遍历到右边的陆地时,当前陆地的左边和上边都是前面的陆地连通过的,再次判断就会重复了。因此,在遍历每一块陆地时,只需要判断其左边和上边的是否可以连通,而右边和下边留给后面的陆地去做判断。

解题步骤

  1. 创建并查集,并查集的大小为 m * n (m = grid.length n = grid[0].length)
  2. 遍历二维数组,如果当前位置的值为 1,再判断其上边和左边是否为 1,如果为 1 则进行连通
  3. 再次遍历二维数组,检查并查集中有多少个集合,就有多少个岛屿

解题代码

var numIslands = function(grid) {
    const m = grid.length, n = grid[0].length
    const unionSet = new UnionSet(m * n)
    
    // 将每个点转成数字表示
    let index = (i, j) => i * n + j
    
    for (let i = 0; i < m; i++) {
        for (let j = 0; j < n; j++) {
            // 如果当前位置表示 水,不需要进行连通性判断
            if (grid[i][j] === '0') continue
            // 当前点不是在最上方,才需要判断上方的点
            if (i > 0 && grid[i - 1][j] === '1') unionSet.merge(index(i, j), index(i - 1, j))
            // 当前点不是在最左,才需要判断左边的点
            if (j > 0 && grid[i][j - 1] === '1') unionSet.merge(index(i, j), index(i, j - 1))
        }
    }
    let sum = 0
    for(let i = 0; i < row; i++) {
        for(let j = 0; j < col; j++) {
            if(grid[i][j] === '1' && unionSet.find(index(i, j)) === index(i, j)) sum++
        }
    }
    return sum
};

// 并查集
class UnionSet {
    constructor(n) {
        this.fa = []
        for (let i = 0; i < n; i++) {
            this.fa[i] = i
        }
    }

    find(v) {
        if(this.fa[v] === v) return v
        const root = this.find(this.fa[v])
        this.fa[v] = root
        return root
    }

    merge(a, b) {
        const sa = this.find(a), sb = this.find(b)
        if (sa === sb) return
        this.fa[sa] = sb
    }
}