文章目录
https://leetcode-cn.com/problems/number-of-provinces/
并查集 disjoint set
class Solution {
public:
int cityNum = 0; //城市数量
int *parent = nullptr; //记录并查集每个节点的父节点
int *rank = nullptr; //记录并查集每个节点的深度
void initialize() {
//初始化并查集
parent = new int[cityNum]();
rank = new int[cityNum](); //并查集每个节点深度为0
for (int i = 0; i < cityNum; i++) {
/*
并查集每个节点的父节点为 -1,
-1 表示没有父节点,
即代表为根节点。
*/
parent[i] = -1;
}
}
int find_root(int x) {
//寻找并查集中节点的父节点
int xRoot = x; //xRoot 为 x 的根节点, 初始为自己
while (parent[xRoot] != -1) { //如果 parent[xRoot] == -1, xRoot 即为 x 的根节点
xRoot = parent[xRoot]; //如果 parent[xRoot] != -1, xRoot 还有父节点, 我们要寻找到 x 的根节点
}
return xRoot;
}
void merge(int x, int y) {
//连接 x 和 y 节点
int xRoot = find_root(x); //xRoot 为 x 的根节点
int yRoot = find_root(y); //yRoot 为 y 的根节点
if (xRoot == yRoot) { //如果 x 与 y 的根节点相同, x 与 y 已经相连
return;
}
//路径压缩
/*
如果 xRoot 的深度大于 yRoot 的深度,
把 yRoot 的父节点设为 xRoot,
这样 xRoot 的深度没有增加, yRoot 也没有增加。
如果反过来, yRoot 的深度就等于 xRoot 的深度加 1,
这样持续下去, 深度就会变成最长, 一条直线。
*/
if (rank[xRoot] > rank[yRoot]) {
parent[yRoot] = xRoot;
}
else if (rank[yRoot] > rank[xRoot]) {
parent[xRoot] = yRoot;
}
else {
/*
如果 xRoot 和 yRoot 的深度相同,
随机设置,
这里选择 xRoot 的父节点设置为 yRoot,
yRoot 的深度加 1。
*/
parent[xRoot] = yRoot;
rank[yRoot]++;
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
cityNum = isConnected.size(); //获取城市数量
initialize(); //初始化并查集
for (int i = 0; i < cityNum - 1; i++) {
for (int j = i + 1; j < cityNum; j++) {
if (isConnected[i][j])
/*
遍历无向图所有情况,
如果相连,
调用 merge 方法将两个节点连接起来。
*/
merge(i, j);
}
}
int proNum = 0; //省份数量
for (int i = 0; i < cityNum; i++) {
if (parent[i] == -1) {
/*
有多少个根节点就有多少个省份
*/
proNum++;
}
}
return proNum;
}
};