【力扣】1319. 连通网络的操作次数

以下为力扣官方题解

1319. 连通网络的操作次数

  • 题目
  • 示例1
  • 示例2
  • 示例3
  • 示例4
  • 提示
  • 官方题解
    • 思路一 深度优先搜索
      • 代码
      • 复杂度分析
    • 思路二 并查集
      • 代码
      • 复杂度分析

题目

用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。

示例1

【力扣】1319. 连通网络的操作次数_第1张图片

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

示例2

【力扣】1319. 连通网络的操作次数_第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]
  • 没有重复的连接。
  • 两台计算机不会通过多条线缆连接。

官方题解

当计算机的数量为 n 时,我们至少需要 n−1 根线才能将它们进行连接。如果线的数量少于 n−1,那么我们无论如何都无法将这 n 台计算机进行连接。因此如果数组 connections 的长度小于 n−1,我们可以直接返回 −1 作为答案,否则我们一定可以找到一种操作方式。

思路一 深度优先搜索

我们可以使用深度优先搜索来得到图中的连通分量数。

具体地,初始时所有节点的状态均为「待搜索」。我们每次选择一个「待搜索」的节点,从该节点开始进行深度优先搜索,并将所有搜索到的节点的状态更改为「已搜索」,这样我们就找到了一个连通分量。

代码

class Solution {
    List<Integer>[] edges;
    boolean[] used;

    public int makeConnected(int n, int[][] connections) {
        if (connections.length < n-1) {
            return -1;
        }

        edges = new List[n];
        for (int i=0; i<n; ++i) {
            edges[i] = new ArrayList<Integer>();
        }
        for (int[] conn : connections) {
            edges[conn[0]].add(conn[1]);
            edges[conn[1]].add(conn[0]);
        }
        
        used = new boolean[n];
        int ans = 0;
        for (int i=0; i<n; ++i) {
            if (!used[i]) {
                dfs(i);
                ++ans;
            }
        }
        
        return ans-1;
    }

    public void dfs(int u) {
        used[u] = true;
        for (int v : edges[u]) {
            if (!used[v]) {
                dfs(v);
            }
        }
    }
}

复杂度分析

  • 时间复杂度:O(n+m),其中 m 是数组 connections 的长度。
  • 空间复杂度:O(n+m),其中 O(m) 为存储所有边需要的空间,O(n) 为深度优先搜索中使用的栈空间。

思路二 并查集

我们可以使用并查集来得到图中的连通分量数。

并查集本身就是用来维护连通性的数据结构。如果其包含 n 个节点,那么初始时连通分量数为 n,每成功进行一次合并操作,连通分量数就会减少 1。

代码

class Solution {
    public int makeConnected(int n, int[][] connections) {
        if (connections.length < n-1) {
            return -1;
        }

        UnionFind uf = new UnionFind(n);
        for (int[] conn : connections) {
            uf.unite(conn[0], conn[1]);
        }

        return uf.setCount-1;
    }
}

// 并查集模板
class UnionFind {
    int[] parent;
    int[] size;
    int n;
    // 当前连通分量数目
    int setCount;

    public UnionFind(int n) {
        this.n = n;
        this.setCount = n;
        this.parent = new int[n];
        this.size = new int[n];
        Arrays.fill(size, 1);
        for (int i=0; i<n; ++i) {
            parent[i] = i;
        }
    }
    
    public int findset(int x) {
        return parent[x] == x ? x : (parent[x] = findset(parent[x]));
    }
    
    public boolean unite(int x, int y) {
        x = findset(x);
        y = findset(y);
        if (x == y) {
            return false;
        }
        if (size[x] < size[y]) {
            int temp = x;
            x = y;
            y = temp;
        }
        parent[y] = x;
        size[x] += size[y];
        --setCount;
        return true;
    }
    
    public boolean connected(int x, int y) {
        x = findset(x);
        y = findset(y);
        return x == y;
    }
}

复杂度分析

  • 时间复杂度:O(m⋅α(n)),其中 m 是数组 connections 的长度,α 是阿克曼函数的反函数。
  • 空间复杂度:O(n),即为并查集需要使用的空间。

你可能感兴趣的:(力扣,leetcode,java)