题目链接: 547. 省份数量 - 力扣(LeetCode)
题目描述:
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
方法一:
按秩合并:对于每个结点,维护一个秩,表示以该结点为根的子树高度的一个上界。按秩合并策略让具有较小秩的根指向具有较大秩的根。
这里每个结点的秩为负数并且初始化为-1,所以数字越小说明实际上秩越大。
class Solution {
public:
class province
{
public:
//如果x是根节点,parent[x]保存节点x的秩的相反数;如果x不是根节点,parent[x]保存节点x的父亲节点
//这里数组原本的命名是father,但是寻找根节点是用find()函数,因为经常混淆,所以这里改名为parent好点
vector<int> parent;
province(int n)
{
//一开始每个节点的parent数组的值初始化为只有一个节点的树的高度
//我原本习惯初始化为-1,但吉大教材中树的高度是从0开始的,因此这里改为初始化为0比较好
parent.resize(n, 0);
}
//寻找节点x的根节点
int Find(int x)
{
//如果秩是负数或0,说明是根节点
if (parent[x] <= 0)
{
return x;
}
//否则就继续寻找根节点,并且使用路径压缩,将各个节点指向根节点。
//在Union操作中,如果将树A的根节点连接到另一棵树B的根节点上,那么只有树A根节点的parent数组的值改变了
//树A中其他节点的parent数组还是指向了原来的根节点,这样不利于后续的查找速度,所以在这里使用路径压缩
return parent[x] = Find(parent[x]);
}
//合并两棵树,将较小的树合并到较大的树上去
void Union(int x, int y)
{
//fx和fy分别是节点x和节点y所在的树的根节点
//这里不能用parent[x]和parent[fy],因为对于根节点,parent数组中存储的是秩
//对于非根节点,没有经过路径压缩,parent数组中存储的不一定就是真正的根节点
int fx = Find(x);
int fy = Find(y);
//如果节点x和节点y的根节点相同,说明处在同一棵树上,直接返回
if (fx == fy)
{
return;
}
//如果不在同一棵树上,就比较他们的树的秩的大小,即根节点的parent数组值的大小
//如果x所在的树的秩比y所在的树的秩大,就把y所在的树接到x所在的树上
if (parent[fx] < parent[fy])
{
parent[fy] = fx;
}
else
{
//否则,就把x所在的树接到y所在的树上
//其中,但两棵树的秩相等时,需要先将y所在树的秩的负数-1
if (parent[fx] == parent[fy])
{
parent[fy]--;
}
parent[fx] = fy;
}
}
};
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size();
province p(n);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (isConnected[i][j] == 1)
{
//如果i和j的根节点相同,则在同一棵树上
//其实这一步也可以不用判断,直接调用p.unioncity()函数即可,因为该函数中也有判断两个节点是否在同一棵树上
if (p.Find(i) == p.Find(j))
{
continue;
}
//否则就连接对应的两棵树
else
{
p.Union(i, j);
}
}
}
}
set<int> sets;
//寻找有几个根节点,即有几个省份
for (int i = 0; i < n; i++)
{
//注意,这里找i的根节点时不能用parent[i],因为如果i是根节点,那么parent[x]保存的是节点x的秩的相反数
//如果i不是根节点,那么可能parent[i]还未经过路径压缩,因此parent[i]不一定是i现在的根节点
sets.insert(p.Find(i));
}
return sets.size();
}
};
练习一下并查集的题目,好久没用过了,关于find()函数和father数组的区别都搞得有点晕乎乎的

本文通过解决LeetCode上的“省份数量”问题,介绍了并查集数据结构的应用。具体讲解了如何利用并查集来确定图中连通组件的数量,并详细解释了按秩合并的策略以提高效率。
392

被折叠的 条评论
为什么被折叠?



