用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。
示例 1:
输入: n = 4, connections = [[0,1],[0,2],[1,2]]
输出: 1
解释: 拔下计算机 1 和 2 之间的线缆,并将它插到计算机 1 和 3 上。
示例 2:
输入: n = 6, connections = [[0,1],[0,2],[0,3],[1,2],[1,3]]
输出: 2
示例 3:
输入: n = 6, connections = [[0,1],[0,2],[0,3],[1,2]]
输出: -1
解释: 线缆数量不足。
示例 4:
输入: n = 5, connections = [[0,1],[0,2],[3,4],[2,3]]
输出: 0
提示:
1 <= n <= 10^51 <= connections.length <= min(n*(n-1)/2, 10^5)connections[i].length == 20 <= connections[i][0], connections[i][1] < nconnections[i][0] != connections[i][1]- 没有重复的连接。
- 两台计算机不会通过多条线缆连接。
解题思路
首先特判一下如果网线数量比计算机数量-1还要少,则无法将所有计算机连成一个网络,返回 -1。
否则将每台计算机看到一个集合,遍历输入数组,连接两台计算机,即将两台计算机合并为一个集合。
最后获取集合数量,集合数量-1,就是没有被连接的计算机数量,也就是最少的操作次数(因为每一台没被连接的计算机都需要连接,即操作一次)。
这种涉及到集合维护的问题,可以用并查集来解题。如果你对 并查集 还不了解,可以看我这一篇文章 数据结构-并查集,文中介绍了并查集的概念、应用场景以及手写实现的全过程。
代码实现
class UnionSet {
constructor(n){
// 初始化节点数量数组
this.size = Array(n).fill(1);
// 初始化集合列表,每一个节点为一个集合
this.list = Array(n);
for(let i = 0;i<n;i++){
this.list[i] = i;
}
}
// 递归获取元素所在集合根节点
find(x){
if(this.list[x]===x) return x;
// 获取到元素所在集合根节点
const root = this.find(this.list[x]);
// 将当前节点挂载为根节点子节点,压缩路径
this.list[x] = root;
return root;
}
// 合并两个元素所在集合
merge(a,b){
// 获取两个元素所在集合的根节点
const rootA = this.find(a),
rootB = this.find(b);
// 如果两个根节点相同,则两元素处于同一集合,无需再合并
if(rootA===rootB) return;
// 如果 a 所在集合元素数量更多,将 b 所在集合合并到 a 所在集合
if(this.size[rootA]>this.size[rootB]){
this.list[rootB] = rootA;
this.size[rootA] += this.size[rootB]
}else{
// 反之将 a 所在集合合并到 b 所在集合
this.list[rootA] = rootB;
this.size[rootB] += this.size[rootA]
}
}
}
var makeConnected = function(n, connections) {
// 获取网线数量
const len = connections.length;
// 如果网线数量比计算机数量-1还少,则无法连接所有计算机
if(len<n-1) return -1;
// 创建并查集实例
const unionset = new UnionSet(n);
// 遍历连接
for(let i = 0;i<len;i++){
// 将两台电脑放入一个集合
unionset.merge(connections[i][0],connections[i][1])
}
// 获取最后并查集中集合数量
const set = new Set();
for(let i = 0;i<n;i++){
set.add(unionset.find(i))
}
// 集合数量-1即未连接电脑数量,也就是最少操作次数
return set.size-1;
};
至此我们就完成了 leetcode-1319-连通网络的操作次数
如有任何问题或建议,欢迎留言讨论!