用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。
示例 1:
0 --- 1
| /
| /
| /
2 / 3
0 --- 1
| |
| |
2 --- 3
输入:n = 4, connections = [[0,1],[0,2],[1,2]]
输出:1
解释:拔下计算机 1 和 2 之间的线缆,并将它插到计算机 1 和 3 上。
解题思路
条件给出:没有重复的连接。
这一题可以用并查集获取剩余未直连的计算机数量,剩余未直连的计算机数量所需要的线缆数。
- 首先连接计算机所需线缆数量为计算机数量减1个。
- 判断线缆数是否小于计算机数量减1个:如果小于则线缆数不够;负责线缆数足够
- 在线缆数足够的情况的下,我们需要先直连已连接的计算机,得到未直连得计算机数量
- 此时要将所有得计算机连通所需要得最少操作次数应该为未直连得计算机数量减1
代码
class UnionSet {
constructor(n) {
this.parent = new Array(n + 1).fill(0).map((v, index) => index)
this.rank = new Array(n + 1).fill(1)
this.count = n
}
getCount() {
return this.count
}
connected(a, b) {
return this.find(a) == this.find(b)
}
find(x) {
if (this.parent[x] != x) {
this.parent[x] = this.find(this.parent[x])
}
return this.parent[x]
}
merge(a, b) {
let ra = this.find(a), rb = this.find(b)
if (ra == rb) return
if (this.rank[ra] < this.rank[rb]) {
this.parent[ra] = rb
this.rank[rb] += this.rank[ra]
} else {
this.parent[rb] = ra
this.rank[ra] += this.rank[rb]
}
this.count--
}
}
var makeConnected = function(n, connections) {
// 连接计算机最小操作次数,也就是计算机的数量减1次
// 如果线缆数小于最小操作次数 则线缆数不足
if (connections.length < n - 1) return -1
// 因为以上的判断,所以底下执行都是在线缆充足的情况下
let u = new UnionSet(n)
// 将已有的计算机连通
for (connection of connections) {
u.merge(connection[0], connection[1])
}
// 需要连接未直连的计算机最少操作次数(未直连的计算机数减1)
return u.getCount() - 1
};