用以太网线缆将 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,就是没有被连接的计算机数量,也就是最少的操作次数(因为每一台没被连接的计算机都需要连接,即操作一次)。
代码实现
var makeConnected = function(n, connections) {
if(connections.length < n -1){
return -1;
}
// 没有连接的时候,连通分量为n,每合并一次,连通分量-1;
let uf = new UnionFind(n);
for(conn of connections){
uf.unite(conn[0],conn[1])
}
return uf.getCount() - 1;
};
class UnionFind{
constructor(n){//初始化:并查集里面的所有节点的父节点都是自己
this.parent = new Array(n).fill(0).map((value,index)=>index);
this.size = new Array(n).fill(1); //初始化集合
this.setCount = n;//联通分量
}
findSet(index){
if(this.parent[index] != index){
this.parent[index] = this.findSet(this.parent[index]);
}
return this.parent[index];
}
unite(index1,index2){ //合并
// 拿到他们的丁点坐标
let root1 = this.findSet(index1), root2 = this.findSet(index2)
if(root1 != root2){
// 判断一下各自集合的节点个数,节点少的集合要往节点多的集合上面合并
if(root1 < root2){
[root1,root2] = [root2,root1]
}
// 合并根节点
this.parent[root2] = root1;
// 计算已经合并的节点数量
this.size[root1] += this.size[root2];
this.setCount --;//合并多少,城市数量则减一
}
}
getCount(){
return this.setCount;
}
connected(index1,index2){// 判断两个顶点,是否是一个连通分量
let root1 = this.findSet(index1),root2 = this.findSet(index2);
return root1 == root2;
}
}
至此我们就完成了leetcode-1319-连通网络的操作次数