1319. 连通网络的操作次数
题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/
题目
用以太网线缆将 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^5
1 <= connections.length <= min(n*(n-1)/2, 10^5)
connections[i].length == 2
0 <= connections[i][0], connections[i][1] < n
connections[i][0] != connections[i][1]
- 没有重复的连接。
- 两台计算机不会通过多条线缆连接。
以上图源均来自力扣(LeetCode)
解题思路
思路:并查集
先审题,其中:
- n n n:表示计算机台数,计算机编号从 0 0 0 到 n − 1 n-1 n−1;
- c o n n e c t i o n s connections connections:表示线缆。 c o n n e c t i o n s [ i ] connections[i] connections[i] 中的两个元素 a a a 和 b b b,代表线缆连接 a a a 和 b b b。
当处在同一个网络中,任意一台计算机都可以直接或间接访问其他任意一台计算机。
题目中给出初始布线 c o n n e c t i o n s connections connections,其中可能存在未直连的计算机,允许拨开任意两台直连计算机之间的线缆将未直连的计算机进行连接。求能使所有计算机连通的最少操作次数?若不可能,则返回 − 1 -1 −1。
首先,先讨论不可能的情况。提示中说明【两台计算机不会通过多条线缆连接】,那么要将 n n n 台计算机连通,至少需要 n − 1 n-1 n−1 条线缆,也就说当 c o n n e c t i o n s connections connections 的长度小于 n − 1 n-1 n−1 时,无法连通 n n n 台计算机,直接返回 − 1 -1 −1。
这里我们也可以观察示例 2 2 2 和示例 3 3 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
解释:线缆数量不足。
两个示例 n n n 均为 6 6 6,而示例 2 2 2 中的线缆数为 5 5 5 等于 n − 1 n-1 n−1 可连通所有计算机;
示例 3 3 3 中的线缆数为 4 4 4,由于 4 4 4 小于 ( n − 1 ) (n-1) (n−1),无法连通所有计算机,返回 − 1 -1 −1。
可得结论:当线缆数量大于或等于 n − 1 n-1 n−1 时一定能够通过改动使得所有计算机连通;反之线缆数小于 n − 1 n-1 n−1 时,都不能使所有的计算机进行连通。
所以现在主要需要讨论的就是可使所有计算机连通的最少操作次数的问题?
前面提到,同处一个网络下,任意计算机都可直接或间接访问其他计算。那么在这可以将这些计算机划分为一类,而其他未直连的计算机则各自为一类。
这里借助示例 2 2 2 来用图说明,如下:
如图:
- 编号为 0 、 1 、 2 、 3 0、1、2、3 0、1、2、3 的计算机已连通,划分为一类;
- 编号为 4 4 4 的计算机未与其他计算机直连,分为一类;
- 同样编号为 5 5 5 的计算机未与其他计算机直连,分为一类;
这里,要将 3 3 3 个合为一类,也就是连通所有计算机,最少需要 3 − 1 = 2 3-1=2 3−1=2 条线缆。
将计算机看成图的节点,线缆看成是连接节点的边时,上面的情况则相当于要将三个连通分量进行合并,至少需要 3 − 1 = 2 3-1=2 3−1=2 条边,即是 最少操作次数 = 连通分量数目 - 1。
使用并查集,具体的思路如下:
- 先处理特殊情况,也就是线缆数小于 n − 1 n-1 n−1 时,一定无法连通所有计算机,直接返回 − 1 -1 −1;
- 排除上面的情况时,首先初始化每个计算机为单独一个连通分量,初始连通分量数目为 n n n,用 c o u n t count count 存储;
- 遍历 c o n n e c t i o n s connections connections,根据计算机连接情况进行合并,每合并一次,连通分量的数目减 1 1 1;
- 当遍历完 c o n n e c t i o n s connections connections 且合并完成后,返回 最少操作次数=连通分量数目 - 1。
具体的代码实现如下。
class UnionFind:
def __init__(self, n):
self.parent = [i for i in range(n)]
# 连通分量数目
self.count = n
def find(self, x):
if x != self.parent[x]:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
x_root = self.find(x)
y_root = self.find(y)
if x_root != y_root:
self.parent[x_root] = y_root
# 合并时,连通分量减 1
self.count -= 1
def get_count(self):
return self.count
class Solution:
def makeConnected(self, n: int, connections: List[List[int]]) -> int:
# 处理特殊情况,线缆数小于 n-1,一定无法连通所有计算,返回 -1
m = len(connections)
if n > m + 1:
return -1
uf = UnionFind(n)
for x, y in connections:
uf.union(x, y)
return uf.get_count() - 1
欢迎关注
公众号 【书所集录】
如有错误,烦请指出,欢迎指点交流。若觉得写得还不错,麻烦点个赞👍,谢谢。