前言
经过并查集的升级路线一二三四之后,我们现在得到了一个相对来说比较完美的并查集数据结构,从本篇开始应用这个并查集为我们解决实际的算法问题。
省份数量
力扣547题
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
题目分析
题目中需要计算的省份数量,实际上就是并查集的森林中树的数量,好在我们在并查集结构中已经使用count来标记了并查集中不同树的数量,所以,我们将链接的城市合并后,最终返回并查集中的count值即可。
题目步骤分解
1、构建并查集;
2、n*n矩阵,n代表着分量的数量,初始化并查集的时候,分量个数传入n;
3、遍历二维矩阵,如果对应值是1,就合并两个分量;
4、遍历结束后,返回并查集的count;
书写代码
并查集的准备
class QuickUnionUnionFind {
// 存储连分量
protected int[] id;
// 当前并查集不同的连通分量总数
protected int count;
public QuickUnionUnionFind(int n) {
// 初始化时,没个分量互不连通
this.count = n;
// 初始化一个容纳全量分量的数组
this.id = new int[n];
for (int i = 0; i < n; i++) {
// 没个分量初始值指向自身
id[i] = i;
}
}
void union(int p, int q) {
// 找到p的标识
int pId = find(p);
// 找到q的标识
int qId = find(q);
// 如果两个标识相等,代表已经合并
if (pId == qId) return;
// 如果不相等,直接让分量q的标识指向p
id[pId] = qId;
// 每次合并操作,会降低一个不同分量组
count--;
}
int find(int p) {
// 沿着标识路径一路寻找,直到找到树的标识
while (p != id[p]) p = id[p];
return p;
}
}
算法代码
class Solution {
public int findCircleNum(int[][] isConnected) {
// n为分量总数
int n = isConnected.length;
QuickUnionUnionFind quuf = new QuickUnionUnionFind(n);
for (int i = 0; i < isConnected.length; i++) {
int[] row = isConnected[i];
for (int k = i; k < row.length; k++) {
if (isConnected[i][k] == 1) {
// 如果矩阵值为1,代表连通,需要合并
quuf.union(i, k);
}
}
}
// 返回树的个数
return quuf.count;
}
}
网友评论