[路飞]_连通网络的操作次数

「这是我参与2022首次更文挑战的第33天,活动详情查看:2022首次更文挑战

leetcode-1319 连通网络的操作次数

题目介绍

用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b

网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。

给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。

示例1

image.png

输入:n = 4, connections = [[0,1],[0,2],[1,2]]
输出:1
解释:拔下计算机 12 之间的线缆,并将它插到计算机 13 上。
复制代码

示例2

image.png

输入: 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]
  • 没有重复的连接。
  • 两台计算机不会通过多条线缆连接。

解题思路

如果要将 n 台计算机通过电缆连接成一个网络,使任意两台计算机都能通过直接或间接的方式访问到对方,最少需要的电缆数是 n - 1,并且题目给出的每一个 connections[i] 就代表一条电缆,因此我们可以得出不可能进行操作的条件,那就是 connections.length < n - 1,即电缆数量不够

那么如何判断最少需要操作的次数,看下图

1645289797(1).png
看一下 示例1 中的例子,计算机之间的连通关系将这 4 台计算机分成了 2 个集合,那么如果要将这两个集合连接起来,最少我们需要 1 根电缆,因此最少操作次数是 1

1645290049(1).png
示例2 的例子中,计算机的连通关系将计算机分成了 3 个集合,要将这 3 个集合进行连接,至少需要 2 根电缆,因此,最少的操作次数是 2

经过上面的分析,其实解法就很明显了。首先根据题目给出的电缆的连通关系,计算将所有的计算机分成了多少个集合 n,那么将这 n 个集合连接起来的最少次数就是 n - 1

可以利用并查集来解决这道题

解题步骤

  1. 判断 connections 数组的长度是否小于计算机的数量 - 1(n - 1
  2. 定义一个并查集,大小为计算机的数量 n
  3. 遍历 connections 数组,将遍历到的每一个数组中的两个计算机进行连接
  4. 统计并查集中有多少个集合
  5. 最少操作次数为 集合数 - 1

解题代码

var makeConnected = function(n, connections) {
    // 判断电缆数量是否足够
    if (connections.length < n - 1) return -1
    
    // 定义并查集
    const unionSet = new UnionSet(n)
    for (const connection of connections) {
        // 根据 connections 中的连通关系将计算机进行连接
        unionSet.merge(connection[0], connection[1])
    }
    
    let num = 0
    for (let i = 0; i < n; i++) {
        // 计算并查集中的集合数量
        if (unionSet.get(i) === i) num++
    }
    
    // 最小操作次数 = 集合数 - 1
    return num - 1
};

// 并查集
class UnionSet {
    constructor (n) {
        this.fa = []
        this.size = []
        for (let i = 0; i < n; i++) {
            this.fa[i] = i
            this.size[i] = 1
        }
    }

    get (v) {
        if (this.fa[v] === v) return v
        const root = this.get(this.fa[v])
        this.fa[v] = root
        return root
    }

    merge (a, b) {
        const ra = this.get(a), rb = this.get(b)
        if (ra === rb) return 
        if (this.size[ra] < this.size[rb]) {
            this.fa[ra] = rb
            this.size[rb] += this.size[ra]
        } else {
            this.fa[rb] = ra
            this.size[ra] += this.size[rb]
        }
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7066468475937488909