题目来源:LeetCode 547. 省份数量
有 n
个城市,其中一些彼此相连,另一些没有相连。如果城市 a
与城市 b
直接相连,且城市 b
与城市 c
直接相连,那么城市 a
与城市 c
间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n
的矩阵 isConnected
,其中 isConnected[i][j] = 1
表示第 i
个城市和第 j
个城市直接相连,而 isConnected[i][j] = 0
表示二者不直接相连。
返回矩阵中 省份 的数量。
示例1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例2:
输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
限制:
- 1 <= n <= 200
- n == isConnected.length
- n == isConnected[i].length
- isConnected[i][j] 为 1 或 0
- isConnected[i][i] == 1
- isConnected[i][j] == isConnected[j][i]
并查集解法
使用quick find
class UnionFind {
constructor(len) {
this.root = Array(len).fill(0).map((_, i) => i);
}
find(x) {
return this.root[x];
}
union(x, y) {
let rootx = this.find(x), rooty = this.find(y);
if(rootx !== rooty) {
for(let i = 0;i<this.root.length;i++) {
if(this.root[i] === rootx) this.root[i] = rooty;
}
}
}
getNums() {
return new Set(this.root).size;
}
}
var findCircleNum = function(isConnected) {
// quick find
const uf = new UnionFind(isConnected.length);
for(const [i, vals] of isConnected.entries()) {
for(const [j, val] of vals.entries()) {
if(val === 1) uf.union(i, j);
}
}
return uf.getNums();
};
基于路径压缩的按秩合并优化的「并查集」
class UnionFind {
constructor(len) {
this.root = Array(len)
.fill(0)
.map((_, i) => i);
this.rank = Array(len).fill(1);
this.size = len;
}
// 路径压缩优化版本的 find 函数
find(x) {
if (x === this.root[x]) return x;
return this.root[x] = this.find(this.root[x]);
}
// 按秩合并优化的 union 函数
union(x, y) {
let rootx = this.find(x), rooty = this.find(y);
if(rootx !== rooty) {
if(this.rank[rootx] > this.rank[rooty]) {
this.root[rooty] = rootx;
} else if(this.rank[rootx] < this.rank[rooty]) {
this.root[rootx] = rooty;
} else { // ===
this.root[rootx] = rooty;
this.rank[rooty] += 1;
}
this.size--;
}
}
}
var findCircleNum = function(isConnected) {
const n = isConnected.length;
const uf = new UnionFind(n);
for(let i = 0;i<n;i++) {
for(let j = 0;j<isConnected[i].length;j++) {
if(isConnected[i][j] === 1) uf.union(i, j);
}
}
return uf.size;
};
DFS解法
/**
* @param {number[][]} isConnected
* @return {number}
*/
var findCircleNum = function(isConnected) {
let visited = new Set(),re = 0;
for(let i = 0;i<isConnected.length;i++){
if(!visited.has(i)){
dfs(isConnected,visited,i);
re++;
}
}
return re;
};
function dfs(data,visited,i){
for(let j = 0;j<data.length;j++){
if(data[i][j] === 1 && !visited.has(j)){
visited.add(j);
dfs(data,visited,j);
}
}
}