持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
题目(Number of Islands)
链接:https://leetcode-cn.com/problems/number-of-islands
解决数:3120
通过率:58%
标签:深度优先搜索 广度优先搜索 并查集 数组 矩阵
相关公司:amazon google microsoft
给你一个由 '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.lengthn == grid[i].length1 <= m, n <= 300grid[i][j]的值为'0'或'1'
思路
并查集(union & find):用于处理一些元素的合并和查询问题
Find:确定元素属于哪一个子集,他可以被用来确定两个元素是否属于同一个子集,加入路径压缩,复杂度近乎O(1)
Union:将两个子集合并成同一个集合
// 0,1,2,3
//parent: 0,1,2,3
//size: 1,1,1,1
class UnionFind{
constructor(n){ //构造一个大小为n的集合
this.count = n
this.parent = new Array(n)
this.size = new Array(n) // size数组记录着每棵树的大小
for (let i = 0; i < n; i++) {
this.parent[i] = i; // 自己是自己的parent
this.size[i] = 1;
}
}
union(p,q){ //连通结点p和结点q, p和q都是索引
let rootP = this.find(p);
let rootQ = this.find(q);
if(rootP === rootQ) return
// 元素数量小的接到数量多的下面,这样比较平衡
if (this.size[rootP] > this.size[rootQ]) {
this.parent[rootQ] = rootP;
this.size[rootP] += this.size[rootQ];
} else {
this.parent[rootP] = rootQ;
this.size[rootQ] += this.size[rootP];
}
this.count--;
}
isConnected(p, q) { //判断p,q是否连通
return this.find(p)=== this.find(q)
}
find(x) { //找到x结点的root
while (this.parent[x] != x) {
// 进行路径压缩
this.parent[x] = this.parent[this.parent[x]];
x = this.parent[x];
}
return x;
}
getCount() { //返回子集个数
return this.count;
}
}
// 0,1,2,3
//parent: 0,1,2,3
//rank: 1,1,1,1
//采用rank优化
class UnionFind {
constructor(n) { //构造一个节点数为n的集合
this.count = n //并查集总数
this.parent = new Array(n)
this.rank = new Array(n) // rank数组记录着每棵树的重量
for (let i = 0; i < n; i++) {
this.parent[i] = i; // 自己是自己的parent
this.rank[i] = 1; //每个集合上节点的数量
}
}
union(p, q) { //连通结点p和结点q, p和q都是索引
let rootP = this.find(p);
let rootQ = this.find(q);
if (rootP === rootQ) return
// 深度小的接在深度大元素下
if (this.rank[rootP] > this.rank[rootQ]) {
this.parent[rootQ] = rootP;
} else if (this.rank[rootP] < this.rank[rootQ]) {
this.parent[rootP] = rootQ;
} else {
this.parent[rootP] = rootQ;
this.rank[rootQ]++
}
this.count--;
}
isConnected(p, q) { //判断p,q是否连通
return this.find(p) === this.find(q)
}
find(x) { //找到x结点的root
while (this.parent[x] != x) {
// 进行路径压缩
this.parent[x] = this.parent[this.parent[x]];
x = this.parent[x];
}
return x;
}
getCount() { //返回子集个数
return this.count;
}
}