题目
题目来源:力扣(LeetCode)
给你一个由 ‘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
思路分析
为了求出岛屿的数量,我们可以扫描这个二维网格,如果一个位置为 1,则将其与相邻四个方向上的 1 在并查集中进行合并。最终并查集中连通分量的数目就是岛屿的数量。
/*** @param {character[][]} grid* @return {number}*/// count 在全局定义,且不能在全局中父默认值,否则会导致某些测试用例通不过,这是LeetCode的以雷区let count; // 存储岛屿的数量var numIslands = function (grid) {// 二维数组中数组的长度let m = grid.length;// 二维数组中内部数组的长度let n = grid[0].length;// 实例化并查集let uf = new UnionFind(m * n);count = 0;// 对二维数组进行遍历,如果 grid[i][j] == '1' 时,count++for (let i = 0; i < m; i++) {for (let j = 0; j < n; j++) {if (grid[i][j] == '1') {count++;}}}// 找当前节点的上下左右节点是否为1,如果都为 1 ,则进行合并for (let i = 0; i < m; i++) {for (let j = 0; j < n; j++) {if (grid[i][j] == '1') {//当前岛屿数量加1if (i - 1 >= 0 && grid[(i - 1)][j] == '1') {// 当前节点的上边一个节点uf.unite(i * n + j, (i - 1) * n + j);}if (i + 1 < m && grid[i + 1] [j] == '1') {// 当前节点的下边一个节点uf.unite(i * n + j, (i + 1) * n + j);}if (j - 1 >= 0 && grid[i][j - 1] == '1') {// 当前节点的左边一个节点uf.unite(i * n + j, i * n + j - 1);}//if (j + 1 < n && grid[i] [j + 1] == '1') {// 当前节点的右边一个节点uf.unite(i * n + j, i * n + j + 1);}}}}return count;};class UnionFind {constructor(n) {// 元素所指向的父节点,parent[i] 表示第 i 个元素所指向的父节点// 初始化时, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合this.parent = new Array(n).fill(0).map((value, index) => index);// 树的层数,rank[i] 表示以 i 为根的集合所表示的树的层数this.rank = new Array(n).fill(1);// 节点的个数this.setCount = n;}// 查找过程,查找元素 index 所在集合的编号(查找树的根节点)findSet(index) {// 不断去查询自己的父节点,直至根节点// 根节点的标志是父节点就是本身 parent[index] == indexif (this.parent[index] != index) {// 递归获取节点的父节点this.parent[index] = this.findSet(this.parent[index]);}// 返回根节点return this.parent[index];}// 合并两个集合unite(index1, index2) {let root1 = this.findSet(index1);let root2 = this.findSet(index2);// 根节点不一样,是两个不同的集合(两棵不同的树)if (root1 != root2) {// 根据树的层数合并集合//if (this.rank[root1] < this.rank[root2]) {// 这个判断如果 root2 所在树的层数 大于 root1,就交换两个父节点,这样始终让 root1 为父节点[root1, root2] = [root2, root1];}// 将层数多的集合合并到集合少的集合this.parent[root2] = root1;this.rank[root1] += this.rank[root2];this.setCount--;count--}}getCount() {return this.setCount;}connected(index1, index2) {return this.findSet(index1) === this.findSet(index2);}}
