leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 78 】2021-11-26 - 1319. 连通网络的操作次数 #97

Open azl397985856 opened 2 years ago

azl397985856 commented 2 years ago

1319. 连通网络的操作次数

入选理由

暂无

题目地址

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]
没有重复的连接。
两台计算机不会通过多条线缆连接。
yanglr commented 2 years ago

思路

仔细分析一下, 会发现本题实际上就是要找连通分量的数量。

方法 : 并查集

N个节点只需要n-1条边就可以组成一个connected component (CC)(1棵生成树)。

对于每根电缆,将两侧合并,如果它们已经具有相同的根,例如 在同一个 cc 中,则该电缆是多余的。

确定额外的电缆(可以拔下并使用它们连接其他电缆)以确保 extra cables >= connected groups -1。

实际上, 根本不需要知道需要拆下哪几条边, 只要电缆的数量够就行了!

只要我们有 n-1 根电缆,我们总能找到一种方法来连接所有计算机。

此时问题可以转换为: 找连通分量的数量


代码

实现语言: C++

class Solution {
    vector<int> p;    
public:
    int makeConnected(int n, vector<vector<int>>& connections) {
        if (connections.size() < n - 1)
            return -1;
        p.resize(n);
        iota(p.begin(), p.end(), 0); // 依次填充0 ~ n-1
        for (const auto& c : connections)
            p[find(c[0])] = find(c[1]);

        unordered_set<int> st;
        for (int i = 0; i < n; i++)
            st.insert(find(i));

        return st.size() - 1;
    }
    int find(int x)
    {
        if (p[x] == x) return x;
        p[x] = find(p[x]);
        return p[x];
    };    
};

复杂度分析

ymkymk commented 2 years ago

class Solution { List[] 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) 为深度优先搜索中使用的栈空间。

zhangzz2015 commented 2 years ago

关键点

代码

C++ Code:


struct UF
{
private:
vector<int> parent; 
int count;
public: 

    UF(int n)
    {
        for(int i=0; i< n; i++)
            parent.push_back(i); 
        count = n; 
    }
    void uninTwoNode(int i, int j)
    {
        int parentI = findParent(i);
        int parentJ = findParent(j); 
        if(parentI != parentJ)
        {
           parent[parentI] = parentJ; 
            count--; 
        }
    }

    int findParent(int i)
    {
        while(parent[i] != i)
        {
            parent[i] = parent[parent[i]]; 
            i = parent[i]; 
        }
        return i; 
    }
    int connectedNum()
    {
        return count; 
    }

}; 
class Solution {
public:
    int makeConnected(int n, vector<vector<int>>& connections) {

        //  generate tree. and tree 
        //  connections number is n-1; 
        if(connections.size()<n-1) // is impossible. 
            return -1; 

        UF uf(n); 
        for(int i=0; i< connections.size(); i++)
        {
            uf.uninTwoNode(connections[i][0], connections[i][1]); 
        }

        return uf.connectedNum()-1; 

    }
};
for123s commented 2 years ago

代码

C++ Code:


class Solution {
public:
    vector<int> parent;

    int find(int x)
    {
        if(x!=parent[x])
        {
            parent[x] = find(parent[x]);
            return parent[x];
        }
        return x;
    }

    int makeConnected(int n, vector<vector<int>>& connections) {
        if(n>connections.size()+1)
            return -1;
        for(int i=0;i<n;i++)
            parent.push_back(i);
        for(int i=0;i<connections.size();i++)
            if(find(connections[i][0])!=find(connections[i][1]))
                parent[find(connections[i][0])] = find(connections[i][1]);
        int res = -1;
        unordered_map<int,bool> mp;
        for(int i=0;i<n;i++)
        {
            find(i);
            if(mp.count(parent[i])!=1)
            {
                res++;
                mp[parent[i]] = true;
            }
        }
        return res;
    }
};
skinnyh commented 2 years ago

Note

Solution

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        def find(x):
            while x != root[x]:
                root[x] = root[root[x]]
                x = root[x]
            return x
        def union(x, y):
            nonlocal count
            root_x, root_y = find(x), find(y)
            if root_x != root_y:
                root[root_x] = root_y
                count -= 1

        # To connect all nodes need at least n-1 edges
        if len(connections) < n - 1: return -1
        root = [i for i in range(n)]
        count =  n
        for c in connections:
            union(c[0], c[1])
        return count - 1

Time complexity: O(N)

Space complexity: O(N)

yingliucreates commented 2 years ago

link:

https://leetcode.com/problems/number-of-operations-to-make-network-connected/

代码 Javascript

const makeConnected = function(n, connections) {
    let edges = connections.length;
    if(edges < n-1) return -1;
    let g = [];
    for(let i=0;i<n;i++) g[i] = []
    for(let i=0;i<edges;i++){
        g[connections[i][0]].push(connections[i][1]);
        g[connections[i][1]].push(connections[i][0]);
    } 
    let v = Array(n).fill(0),c=0;
    for(let i=0;i<n;i++){
        if(!v[i]){
            c++;
            dfs(i,g,v)
        }
    }
    return c-1;
};

function dfs(i,con,v){
    v[i] = 1;
    for(let x of con[i]){
        if(!v[x]) dfs(x,con,v)
    }
}
ZacheryCao commented 2 years ago

Idea:

UnionFind. For n nodes, we need at least n-1 edges to connect them all. If the amount of the edges is fewer than that, we return -1. For each edge, we union its two nodes. After we scan through all edges, we can know how many unions we have now. The difference between the union amount and 1 is the edges we need to extract.

Code:

class UnionFind:
    def __init__(self, n):
        self.parent = {}
        self.size = {}
        self.cnt = n
        for i in range(n):
            self.parent[i] = i
            self.size[i] = 1

    def find(self, p):
        if p!=self.parent[p]:
            self.parent[p] = self.find(self.parent[self.parent[p]])
            return self.parent[p]
        return p

    def union(self, p, q):
        root_p, root_q = self.find(p), self.find(q)
        if root_p != root_q:
            self.parent[root_p] = root_q
            self.size[root_q] += self.size[root_p]
            self.cnt -= 1

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections)< n - 1:
            return -1
        UF = UnionFind(n)
        for i in connections:
            UF.union(i[0], i[1])
        return UF.cnt - 1

Complexity:

Time: O(N +E). N is the is number of the machines. E is the amount of edges. Initializing the union find needs O(N). Scanning through the edges needs O(E). Space: O(N)

joeytor commented 2 years ago

思路

使用并查集的方法

先判断 len(connections) 是否 < n-1, 因为如果小于那么代表无法连接 n 个节点, 返回 -1

否则一定能连接 n 个节点

那么用并查集将现在有的 connection 进行连接

连接后要改动的 minimum number of times 其实就是 现在并查集中联通分量的个数 -1, 因为网线一定够, 所以不需要找到从哪儿拔网线, 只需要计算最少需要添加多少根网线

最少需要添加的网线数目就是现在有的联通分量的个数 -1, 所以遍历 i, 计数不同的 parents ( find(i) 的结果 ) 的个数, 最后返回 不同 parents 的个数 -1

class UF:
    def __init__(self, num):
        self.parents = [i for i in range(num)]

    def find(self, x):
        while self.parents[x] != x:
            self.parents[x] = self.parents[self.parents[x]]
            x = self.parents[x]
        return x

    def isconnected(self, x, y):
        return self.find(x) == self.find(y)

    def union(self, x, y):
        if self.find(x) != self.find(y):
            px, py = self.find(x), self.find(y)
            self.parents[px] = py

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        num = len(connections)
        if num < n-1:
            return -1

        uf = UF(n)

        for i, j in connections:
            uf.union(i, j)

        parents = set()
        for i in range(n):
            pi = uf.find(i)
            parents.add(pi)

        return len(parents)-1

复杂度

n 为 节点个数, m 为 connections 长度

时间复杂度: O((m+n)logn) 进行了 m 次 union, 所以复杂度是 O(mlogn), 进行了 n 次查找 parents, 所以复杂度是 O(nlogn), 综合时间复杂度为 O((m+n)logn)

空间复杂度: O(n) 并查集的空间复杂度是 O(n), parents set 的空间复杂度小于 O(n) 所以总得空间复杂度是 O(n)

zjsuper commented 2 years ago

Idea:union find Time: O(N +E). N is the is number of the machines. E is the amount of edges. Initializing the union find needs O(N). Scanning through the edges needs O(E). Space: O(N)

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections)< n - 1:
            return -1
        uf = UF(n)
        for i in connections:
            uf.union(i[0], i[1])
        return uf.count - 1

class UF:
    def __init__(self,n):
        self.parent = {}
        self.size = {}
        self.count = n
        for i in range(n):
            self.parent[i] = i
            self.size[i] = 1

    def find(self,x):
        while x != self.parent[x]:
            x = self.parent[x]
        return x

    def union(self,x,y):
        if self.connected(x,y): return
        self.parent[self.find(x)] = self.find(y)
        self.size[self.find(x)] += self.size[self.find(y)]
        self.count -= 1

    def connected(self,x,y):
        return self.find(x) == self.find(y)
wenjialu commented 2 years ago

思路

connections 就相当于连接线。

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

先按照连接线连接:连接前判断他们有没有连在一起(find==find),如果没连就连在一起;如果连了这就是多余的线,不做操作。 连接线遍历完之后出现了几个联通分量,就需要联通分量-1条线把他们连起来。 【不用考虑多余的线够不够,直接返回联通分量-1 就好了,因为一开始就判断过了可能性,如果通过的话是一定可能的】

代码

class UF(object):
    def __init__(self, n):
        self.n = n 
        self.parent = list(range(n)) 
        self.size = [1] * n  # ?
        # 连通分量的数量。
        self.count = n

    def find(self, x):

        if x != self.parent[x]:
            # self.parent[x] = self.find( self.parent[x] )
            self.parent[x] = self.find( self.parent[x]  )
            return self.parent[x] 
            # return self.parent # 降低树的高度
        return x  

    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return False
        if self.size[y] < self.size[x]:
            x, y = y, x
        self.parent[x] = y # 小的x挂大的上面,大的y是parent。
        self.size[y] += self.size[x]
        self.count -= 1
        return True 

    def connected(self, x, y):
        return self.find(x) == self.find(y)

class Solution(object):
    def makeConnected(self, n, connections):
        """
        :type n: int
        :type connections: List[List[int]]
        :rtype: int
        """
               uf = UF(n)
        if len(connections) < n -1:
            return -1
        # lines = 0
        for node1, node2 in connections:
            if uf.find(node1) != uf.find(node2):
                uf.union(node1, node2)
            else:
                continue
        return uf.count - 1

复杂度分析

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

heyqz commented 2 years ago
class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n - 1:
            return -1
        parent = {}
        def find(x):
            parent.setdefault(x, x)
            if x != parent[x]:
                parent[x] = find(parent[x])  # path compression
            return parent[x]

        def union(x, y):
            rootX = find(x)
            rootY = find(y)
            if rootX == rootY:
                return
            parent[rootX] = rootY

        for a, b in connections:
            union(a, b)

        k = len(set(map(find, range(n)))) - 1 
        return k
pan-qin commented 2 years ago

Idea:

Connected computers form a connected components. We need to find out the number of connected components CC. If there is only one CC, all computers are connecetd. We don't need any operation. If there are n CC, we need at least n-1 more edges to connected all CCs. If we have greater than or equal to n-1 extra edges in the original network, then we can do n-1 operations to connect. Otherwise, we can't. So use unionfind to count the number of CC, meanwhile also count the extra edges in the orignial network. The extra edges can be obtained by checking if the two computer in connections already have the same root. If yes, this edge is an extra edge.

Complexity:

Time: O(m) m is the length of connections. Space: O(n) n is the number of computer

class Solution {
    public int makeConnected(int n, int[][] connections) {
        UnionFind uf = new UnionFind(n);
        int extra=0;
        for(int i=0;i<connections.length;i++) {
            int a = connections[i][0];
            int b = connections[i][1];
            if(uf.find(a)==uf.find(b))
                extra++;
            else
                uf.union(a,b);
        }
        int cc=uf.count();
        if(cc==1)
            return 0;
        if(extra>=cc-1)
            return cc-1;
        return -1;

    }

    class UnionFind {
        int[] parent;
        int count;

        public UnionFind(int n) {
            parent = new int[n];
            for(int i=0;i<n;i++) {
                parent[i]=i;
            }
            count=n;
        }

        public int find(int x) {
            while(x!=parent[x]) {
                parent[x]=parent[parent[x]];
                x=parent[x];
            }
            return parent[x];
        }

        public void union(int a, int b) {
            int aroot = find(a);
            int broot = find(b);
            if(aroot!=broot) {
                parent[broot]=aroot;
            }
            count--;
        }
        public int count() {
            return count;
        }
    }
}
CoreJa commented 2 years ago

思路

和昨天前天一样也是连通数问题,今天11分半 ide free bug free完成了,但是效果差速度慢,优化发现忘了做路径优化更没有实现降秩操作,而且可以用ans来维护当前连通域数量(每次合并操作自减1即可),优化后速度从584ms到了84ms

  1. 如果connections数量小于n-1,直接返回-1(因为不够使所有点连通)
  2. 初始化ans=n,ans为当前连通域数量
  3. 构建并查集,要有size来降秩并进行路径优化,遍历connections,每次union操作ans-=1
  4. 返回ans-1 (此时的连通域数量-1即为将这几个连通域都连通所需要的连接次数)

代码

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections)<n-1:
            return -1

        uf={}
        size = {}
        ans = n
        # for i in range(n):
        #     uf[i]=i
        for i,j in connections:
            p,q=i,j
            while p!=uf.setdefault(p,p):
                p=uf[p]
            uf[i]=p
            while q!=uf.setdefault(q,q):
                q=uf[q]
            uf[j]=q
            if p!=q:
                if size.setdefault(p,1)>=size.setdefault(q,1):
                    uf[q]=p
                    size[p]+=size[q]
                else:
                    uf[p]=q
                    size[q]+=size[p]
                ans-=1

        return ans-1
JiangyanLiNEU commented 2 years ago
var makeConnected = function(n, connections) {
    let edges = connections.length;
    if(edges < n-1) return -1;
    let g = [];
    for(let i=0;i<n;i++) g[i] = []
    for(let i=0;i<edges;i++){
        g[connections[i][0]].push(connections[i][1]);
        g[connections[i][1]].push(connections[i][0]);
    } 
    let v = Array(n).fill(0),c=0;
    for(let i=0;i<n;i++){
        if(!v[i]){
            c++;
            dfs(i,g,v)
        }
    }
    return c-1;
};
function dfs(i,con,v){
    v[i] = 1;
    for(let x of con[i]){
        if(!v[x]) dfs(x,con,v)
    }
}
pophy commented 2 years ago

思路

Java Code

class Solution {
    public int makeConnected(int n, int[][] connections) {
        if (connections.length < n - 1) return -1; // To connect all nodes need at least n-1 edges
        UF uf = new UF(n);
        int count = 0;
        for (int[] conn : connections) {
            int u = conn[0];
            int v = conn[1];
            if (uf.find(u) == uf.find(v)) {
                count++;
            } else {
                uf.union(u, v);
            }
        }
        return uf.size - 1 <= count ? uf.size - 1 : -1;    
    }
    private static class UF {
        int[] parent;
        int size;
        public UF (int n) {
            parent = new int[n];
            size = n;
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }

        public int find (int x) {
            if (parent[x] != x) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }

        public void union (int x, int y) {
            int pX = find(x);
            int pY = find(y);
           if (pX != pY) {
                parent[pY] = pX;               
                size--;
           }
        }
    }
}

时间&空间

wangzehan123 commented 2 years ago

代码

Java Code:


class Solution {
    public int makeConnected(int n, int[][] connections) {
        if(connections.length < n-1) return -1;
        int count = n;
        int[] checkAndSet = new int[n];
        for(int i = 0;i < n;i++) checkAndSet[i] = i;
        for(int[] con : connections){
            int index1 = con[0];
            int index2 = con[1];
            if(find(checkAndSet,index1) != find(checkAndSet,index2)){
                union(checkAndSet,index1,index2);
                --count;
            }
        }
        return count-1;
    }

    public void union(int[] checkAndSet,int index1,int index2){
        checkAndSet[find(checkAndSet,index1)] = find(checkAndSet,index2);
    }

    public int find(int[] checkAndSet,int index){
        if(checkAndSet[index] != index) checkAndSet[index] = find(checkAndSet,checkAndSet[checkAndSet[index]]);
        return checkAndSet[index];
    }
}
itsjacob commented 2 years ago

Intuition

Implementation

class Solution
{

  class DisjointSet
  {

  private:
    std::vector<int> id;
    std::vector<int> sz;

  public:
    DisjointSet(int n)
    {
      id.resize(n);
      sz.resize(n);
      std::iota(id.begin(), id.end(), 0);
      std::fill(sz.begin(), sz.end(), 1);
    }

    void unite(int x, int y)
    {
      int xId = find(x);
      int yId = find(y);
      if (xId == yId) return;
      if (sz[xId] < sz[yId]) {
        id[xId] = id[yId];
        sz[yId] += sz[xId];
      } else {
        id[yId] = id[xId];
        sz[xId] += sz[yId];
      }
      return;
    }

    int find(int x)
    {
      if (x != id[x]) {
        id[x] = find(id[x]);
      }
      return id[x];
    }
  };

public:
  int makeConnected(int n, vector<vector<int>> &connections)
  {

    // n computers at least need n-1 cables
    if (connections.size() < n - 1) {
      return -1;
    }

    // build the Disjoint set
    DisjointSet ds(n);
    for (auto const &c : connections) {
      ds.unite(c[0], c[1]);
    }

    // count the numbers of disjoint sets
    int res{ 0 };
    for (int ii = 0; ii < n; ii++) {
      if (ds.find(ii) == ii) {
        res++;
      }
    }

    // res is at most n

    // connecting res sets needs res-1 cables
    return res - 1;
  }
};

Complexity

tongxw commented 2 years ago

思路

并查集检查连通分量

代码

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

        Map<Integer, Integer> parents = new HashMap<>();
        for (int i=0; i<n; i++) {
            parents.put(i, null);
        }

        int ans = n;
        for (int[] con: connections) {
            // find
            int root1 = find(parents, con[0]);
            int root2 = find(parents, con[1]);

            // union
            if (root1 != root2) {
                parents.put(root1, root2);
                ans--;
            }
        }

        return ans - 1;
    }

    private int find(Map<Integer, Integer> parents, int node) {
        int root = node;
        while (parents.get(root) != null) {
            root = parents.get(root);
        }

        while (node != root) {
            int oldParent = parents.get(node);
            parents.put(node, root);
            node = oldParent;
        }

        return root;
    }
}

TC: O(E * Log(V)) SC: O(V)

zhangzhengNeu commented 2 years ago

思路 并查集 遍历connections, 对于当前conn 如果conn[0] 和 conn[1]已经相连, 可用连接数count++ 不相连 则union 最后检查UF的size和count做比较,并返回答案 特判:如果n个点相连 则最少需要n-1个边,所以如果connections.length < n - 1,则必然不能联通所有点 Java Code class Solution { public int makeConnected(int n, int[][] connections) { if (connections.length < n - 1) return -1; // To connect all nodes need at least n-1 edges UF uf = new UF(n); int count = 0; for (int[] conn : connections) { int u = conn[0]; int v = conn[1]; if (uf.find(u) == uf.find(v)) { count++; } else { uf.union(u, v); } } return uf.size - 1 <= count ? uf.size - 1 : -1;
} private static class UF { int[] parent; int size; public UF (int n) { parent = new int[n]; size = n; for (int i = 0; i < n; i++) { parent[i] = i; } }

    public int find (int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    public void union (int x, int y) {
        int pX = find(x);
        int pY = find(y);
       if (pX != pY) {
            parent[pY] = pX;               
            size--;
       }
    }
}

} 时间&空间 时间 O(n) n = connections.length 并查集find/union 可以认为是O(1)操作 空间 O(n)

littlemoon-zh commented 2 years ago
class UF:

    def __init__(self, n):
        self.p = [i for i in range(n)]
        self.rank = [1] * n
        self.comp = n

    def union(self, x, y):
        px = self.find(x)
        py = self.find(y)

        if px != py:
            self.comp -= 1
            if self.rank[px] < self.rank[py]:
                self.p[px] = py
                self.rank[py] += self.rank[px]
            else:
                self.p[py] = px
                self.rank[px] += self.rank[py]

    def find(self, x):
        tx = x
        while x != self.p[x]:
            x = self.p[x]

        while tx != x:
            t = self.p[tx]
            tx = self.p[tx]
            tx = t
        return x

class Solution:
    def makeConnected(self, n: int, cs: List[List[int]]) -> int:
        conn = len(cs)
        if conn < n - 1:
            return -1

        uf = UF(n)

        for x, y in cs:
            uf.union(x, y)

        return uf.comp - 1
Tao-Mao commented 2 years ago
class Solution:
    availableWires = 0
    numComponents = 0
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        self.numComponents = n
        parent = [i for i in range(n)]
        def find(p):
            root = p
            while root != parent[root]:
                root = parent[root]
            return root

        def union(p, q):
            root1 = find(p)
            root2 = find(q)
            if root1 == root2:
                self.availableWires += 1
                return
            parent[root2] = root1
            self.numComponents -= 1

        for node in connections:
            union(node[0], node[1])
        if self.numComponents - self.availableWires == 1 or self.availableWires >= self.numComponents :
            return self.numComponents - 1
        return -1

Time: O(E * Log(V)) Space: O(V)

Serena9 commented 2 years ago

代码

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        root = [i for i in range(n)]

        def find(p):
            while p != root[p]:
                root[p] = root[root[p]]
                p = root[p]

            return p

        def union(p, q):
            root[find(p)] = find(q)

        have = 0
        for connec in connections:
            a, b = connec
            if find(a) != find(b):
                union(a, b)
            else:
                have += 1

        diff_root = set()
        for i in range(n):
            diff_root.add(find(i))

        return len(diff_root) - 1 if have >= len(diff_root) - 1 else -1
yachtcoder commented 2 years ago

冰茶几

class UF:
    def __init__(self):
        self.parent = {}
        self.size = defaultdict(lambda: 1)

    def find(self, x):
        #Don't foget this one, this is mandatory as lazy init.
        ox = x
        self.parent.setdefault(x, x)
        while x != self.parent[x]:
            x = self.parent[x]
        self.parent[ox] = x
        return x

    def merge(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py: return
        if self.size[px] < self.size[py]:
            self.parent[px] = py
            self.size[py]  += self.size[px]
        else:
            self.parent[py] = px
            self.size[px] += self.size[py]
    def is_connected(self, x, y):
        return self.find(x) == self.find(y)

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        uf = UF()
        extra = []
        for u, v in connections:
            if uf.is_connected(u, v):
                extra.append((u, v))
            uf.merge(u,v)
        components = set()
        for i in range(n):
            if uf.size[uf.find(i)] != n:
                components.add((uf.find(i), uf.size[uf.find(i)]))
        ret = max(len(components) - 1, 0)
        return ret if ret <= len(extra) else -1 
shawncvv commented 2 years ago

思路

并查集

代码

JavaScript Code

/**
 * @param {number} n
 * @param {number[][]} connections
 * @return {number}
 */
var makeConnected = function (n, connections) {
  // 连接 n 台电脑至少需要 n - 1 根线缆
  if (connections.length < n - 1) {
    return -1;
  }
  // 计算联通分量,最小操作次数就是将联通分量链接的次数
  let father = Array.from({ length: n }, (v, i) => i);
  let count = n;
  for (connection of connections) {
    union(...connection);
  }

  return count - 1;

  function find(v) {
    if (father[v] !== v) {
      father[v] = find(father[v]);
    }
    return father[v];
  }

  function union(x, y) {
    if (find(x) !== find(y)) {
      count--;
      father[find(x)] = find(y);
      // 联通分量数减一
    }
  }
};

复杂度

yan0327 commented 2 years ago

思路: 关键是如果边少于顶点数减一,直接返回-1 其他情况就是对整体进行联合,每联合一次,groupNum-- 最后由groupNum-1可以返回答案

func makeConnected(n int, connections [][]int) int {
    if len(connections) < n-1{
        return -1
    }
    groupNum := n
    parent := make([]int,n)
    var findRoot func(x int) int
    findRoot = func(x int)int{
        if x == parent[x]{
            return x
        }
        parent[x] = findRoot(parent[x])
        return parent[x]
    }
    for i:=0;i<len(parent);i++{
        parent[i] = i
    }
    for i:=0;i<len(connections);i++{
        aRoot := findRoot(connections[i][0])
        bRoot := findRoot(connections[i][1])
        if aRoot != bRoot{
            groupNum--
            parent[aRoot] = bRoot
        }
    }
    return groupNum-1
}

时间复杂度:O(V+E), 其中 V是顶点数, E是边数 空间复杂度:O(V)

shamworld commented 2 years ago
var makeConnected = function(n, connections) {
    // 连接 n 台电脑至少需要 n - 1 根线缆
    if (connections.length < n - 1) {
        return -1;
    }
    let arr = Array.from({length:n},(v,i) => i);
    let count = n;
    for(const connection of connections){
        union(...connection);
    }
    function find(x) {
        if(arr[x] !== x){
            arr[x] = find(arr[x]);
        }
        return arr[x];
    } 
    function union(x,y){
        if(find(x) !== find(y)){
            count--;
            arr[find(x)] =  find(y);
        }

    }
    return count - 1;
};
biancaone commented 2 years ago
class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n - 1:
            return -1
        self.visited = set()

        self.graph = [[] for _ in range(n)]

        count = 0
        for connection in connections:
            self.graph[connection[0]].append(connection[1])
            self.graph[connection[1]].append(connection[0])

        for i in range(n):
            if i not in self.visited:
                self.dfs(i)
                count += 1
        return count - 1

    def dfs(self, i):
        self.visited.add(i)

        for next_node in self.graph[i]:
            if next_node not in self.visited:
                self.dfs(next_node)
watermelonDrip commented 2 years ago
class union_find(object):
    def __init__(self,n):
        self.root = list(range(n))
        self.size = n 
    def find(self,x):
        if self.root[x] ==x:
            return x
        self.root[x] = self.find(self.root[x])
        return self.root[x]

    def union(self,x,y):
        rootx = self.find(x)
        rooty = self.find(y)
        if rootx != rooty:
            self.root[rooty] = rootx
        self.size -=1

    def isconnected(self,x,y):
        return self.find(x) == self.find(y)

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:

        num_lines = len(connections)
        if num_lines< n -1:
            return -1

        uf = union_find(n)

        for i in range(num_lines):
            if uf.isconnected(connections[i][0],connections[i][1]):
                continue
            uf.union(connections[i][0],connections[i][1])

        return uf.size -1
wenlong201807 commented 2 years ago

代码块


var makeConnected = function (n, connections) {
  if (connections.length < n - 1) {
    return -1;
  }
  let groupNum = n;
  let parent = new Array(n);

  const findRoot = (x) => {
    if (x == parent[x]) {
      return x;
    }
    parent[x] = findRoot(parent[x]);
    return parent[x];
  };

  for (let i = 0; i < parent.length; i++) {
    parent[i] = i;
  }

  for (let i = 0; i < connections.length; i++) {
    const aRoot = findRoot(connections[i][0]);
    const bRoot = findRoot(connections[i][1]);
    if (aRoot != bRoot) {
      groupNum--;
      parent[aRoot] = bRoot;
    }
  }
  return groupNum - 1;
};

时间复杂度和空间复杂度

chun1hao commented 2 years ago
var makeConnected = function (n, connections) {
  if (connections.length < n - 1) return -1;
  let uf = new UnionFind(n);
  for (let [i, j] of connections) {
    uf.union(i, j);
  }
  return uf.count - 1;
};
class UnionFind {
  constructor(n) {
    this.count = n;
    this.parent = Array.from({ length: n }, (i, idx) => idx);
  }
  find(x) {
    if (this.parent[x] !== x) {
      this.parent[x] = this.find(this.parent[x]);
    }
    return this.parent[x];
  }
  union(x, y) {
    if (this.find(x) === this.find(y)) return;
    this.parent[this.parent[x]] = this.parent[y];
    this.count--;
  }
15691894985 commented 2 years ago

【Day 78】1319. 连通网络的操作次数

https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/

思考:

   class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n - 1:
            return -1
        root = [i for i in range(n)]

        def find(p):
            while p != root[p]:
                root[p] = root[root[p]]
                p = root[p]
            return p

        def union(p, q):
            root[find(p)] = find(q)
        have = 0
        for  a, b in connections:
            if find(a) != find(b):
                union(a, b)
            else:
                have += 1  #联通的点
         diff_root = set()
         for i in range(n):
            diff_root.add(find(i)) #独立集合的个数
         return len(diff_root) - 1 if have >= len(diff_root) - 1 else -1

时间复杂度:O(N a(N) 合并与查找时间复杂度为 O(logx)和 O(logy)

空间复杂度:O(n)

kennyxcao commented 2 years ago

1319. Number of Operations to Make Network Connected

Intuition

Code

/**
 * @param {number} n
 * @param {number[][]} connections
 * @return {number}
 */
const makeConnected = function(n, connections) {
  const dsu = new DSU(n);
  let extraEdges = 0;
  for (const [a, b] of connections) {
    const currCount = dsu.count;
    dsu.union(a, b);
    extraEdges += dsu.count === currCount ? 1 : 0; // extra connection if a and b are already linked
  }
  const unlinkedComputers = dsu.count - 1; // substract one from linked group
  return extraEdges >= unlinkedComputers ? unlinkedComputers : -1;
};

class DSU {
  constructor(n) {
    this.parent = Array.from(Array(n).keys());
    this.count = n;
  }

  find(x) {
    if (this.parent[x] !== x) {
      this.parent[x] = this.find(this.parent[x]);
    }
    return this.parent[x];
  }

  union(x, y) {
    const rootX = this.find(x);
    const rootY = this.find(y);
    if (rootX !== rootY) {
      this.parent[Math.min(rootX, rootY)] = Math.max(rootX, rootY);
      this.count -= 1;
    }
  }
}

Complexity Analysis

Zhang6260 commented 2 years ago

JAVA版本

思路:

就简单的运用交叉集,但主要返回-1的情况,线段小于点的个数减一则必不能,还有就是进行合并集合的时候,进行一下判断可以提高运行效率(力扣上35ms->2ms)

class Solution {
    int[]parent;
    public int makeConnected(int n, int[][] connections) {
        if(connections.length<n-1)return -1;
        //使用交查集  connection是边  边的长度 必须大于等于n-1
        int size = n;
        parent = new int[size];
        //初始化
        int res = size;
        for(int i=0;i<size;i++){
            parent[i] = i;
        }
        for(int i=0;i<connections.length;i++){
            if(unite(connections[i][0],connections[i][1])){
                res--;
            }
        }
        return res-1;
    }
    private int findset(int x){
        return parent[x]==x?x:(findset(parent[x]));
    }
    private boolean unite(int a,int b){
        int x = findset(a);
        int y = findset(b);
        if(x==y)return false;
          //这个判断可以起到优化的作用 
        if(x<y){
            parent[y]=x;
        }else{
            parent[x]=y;
        }
        return true;
    }
}

时间复杂度:O(elogv)

空间复杂度:O(v)

ai2095 commented 2 years ago

1319. Number of Operations to Make Network Connected

https://leetcode.com/problems/number-of-operations-to-make-network-connected/

Topics

-DFS

思路

DFS

代码 Python

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        # 排除边不够的情况
        if len(connections) < n - 1:
            return -1
        self.visited = set()

        #建图
        self.graph = [[] for _ in range(n)]

        count = 0
        for connection in connections:
            self.graph[connection[0]].append(connection[1])
            self.graph[connection[1]].append(connection[0])
        #逐个node排查,找出联通子图个数
        for i in range(n):
            if i not in self.visited:
                self.dfs(i)
                count += 1
        return count - 1

    #用dfs来找联通子图
    def dfs(self, i):
        self.visited.add(i)
        for next_node in self.graph[i]:
            if next_node not in self.visited:
                self.dfs(next_node)

复杂度分析

时间复杂度: O(N)
空间复杂度:O(N)

naomiwufzz commented 2 years ago

思路:并查集

连接n个网络,需要n-1条线,如果线少于n-1肯定是无法连通的。如果已经有k块连通分量了,那只需要k-1根线把他们连起来

代码

class UnionFind:
    def __init__(self, n):
        self.parent = {}
        self.size = {}
        self.cnt = 0
        for i in range(n):
            self.parent[i] = i
            self.size[i] = 1
            self.cnt += 1
    def find(self, x):
        while x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]
        return x
    def union(self, p, q):
        parent_p, parent_q = self.find(p), self.find(q)
        if parent_p == parent_q:
            return
        if self.size[parent_p] > self.size[parent_q]:
            self.parent[parent_q] = self.parent[parent_p]
            self.size[parent_p] += self.size[parent_q]
        else:
            self.parent[parent_p] = self.parent[parent_q]
            self.size[parent_q] += self.size[parent_p]
        self.cnt -= 1

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        # n个节点起码要n-1根线
        if len(connections) < n-1:
            return -1
        uf = UnionFind(n)
        for i, j in connections:
            uf.union(i, j)
        return uf.cnt - 1

复杂度分析

Moin-Jer commented 2 years ago

思路


并查集

代码


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;
    }
}

复杂度分析


ysy0707 commented 2 years ago

查并集复制题解

class Solution {
    public int makeConnected(int n, int[][] connections) {
        int m = connections.length;
        UnionFind uf = new UnionFind(n);
        // 非必要连接
        int noNeedNum = 0;
        for(int i=0;i<m;i++){
            int from = connections[i][0];
            int to = connections[i][1];
            if(uf.find(from)==uf.find(to)) noNeedNum++; // 不是必要的连接
            else uf.union(from,to); // 是必要的连接
        }
        if(uf.size==1) return 0; // 这些连接已经可以完成整体连接
        if(noNeedNum >= uf.size - 1) return uf.size - 1; // 非必要连接足够支持剩余连通分量
        return -1;
    }
}

class UnionFind{
    int size;
    int[] parent;

    public UnionFind(int n){
        size = n;
        parent = new int[n];
        for(int i=0;i<n;i++){
            parent[i]=i;
        }
    }

    public int find(int node){
        if(parent[node]==node) return node;
        else return parent[node]=find(parent[node]);
    }

    public void union(int x,int y){
        int rootX = find(x);
        int rootY = find(y);
        if(rootX==rootY) return ;
        parent[rootX] = rootY;
        size--;
    }
}

时间复杂度:O(N) 空间复杂度:O(N)

L-SUI commented 2 years ago

/**

const dfs = (u, used, edges) => { used[u] = 1; if (edges.get(u)) { for (const v of edges.get(u)) { if (!used[v]) { dfs(v, used, edges); } } } }

AgathaWang commented 2 years ago
class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        root = [i for i in range(n)]

        def find(p):
            while p != root[p]:
                root[p] = root[root[p]]
                p = root[p]

            return p

        def union(p, q):
            root[find(p)] = find(q)

        have = 0
        for connec in connections:
            a, b = connec
            if find(a) != find(b):
                union(a, b)
            else:
                have += 1

        diff_root = set()
        for i in range(n):
            diff_root.add(find(i))

        return len(diff_root) - 1 if have >= len(diff_root) - 1 else -1
ghost commented 2 years ago

题目

  1. Number of Operations to Make Network Connected

思路

DFS

代码

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n-1: return -1

        isolated = 0
        G = [set() for _ in range(n)]
        visited = [False] * n

        for i,j in connections:
            G[i].add(j)
            G[j].add(i)

        def dfs(i):
            if visited[i] : return 0
            visited[i] = True
            for j in G[i] : 
                #visited[j] = True
                dfs(j)
            return 1

        for i in range(n):
            if not visited[i] : isolated += dfs(i)

        return isolated - 1

复杂度

Space: O(n) Time: O(max(n, connections))

thinkfurther commented 2 years ago

···python3 class Solution: def makeConnected(self, n: int, connections: List[List[int]]) -> int: root = [i for i in range(n)]

    def find(p):
        while p != root[p]:
            root[p] = root[root[p]]
            p = root[p]

        return p

    def union(p, q):
        root[find(p)] = find(q)

    have = 0
    for connec in connections:
        a, b = connec
        if find(a) != find(b):
            union(a, b)
        else:
            have += 1

    diff_root = set()
    for i in range(n):
        diff_root.add(find(i))

    return len(diff_root) - 1 if have >= len(diff_root) - 1 else -1
kidexp commented 2 years ago

thoughts

用union find 找有多少个连通图假设为k, 那么k-1就是所求 前提connections 里面要有至少n-1个边

code

class UF:
    def __init__(self, n) -> None:
        self.parent = {i: i for i in range(n)}

    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]

    def connect(self, i, j):
        root_i, root_j = self.find(i), self.find(j)
        if root_i != root_j:
            self.parent[root_i] = root_j

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n - 1:
            return -1
        uf = UF(n)
        for node1, node2 in connections:
            uf.connect(node1, node2)
        root_set = set()
        for node in range(n):
            root_set.add(uf.find(node))
        return len(root_set) - 1

complexity

m为connection的个数 Time O(m+n) Space O(n)

hewenyi666 commented 2 years ago

题目名称

1319. 连通网络的操作次数

题目链接

https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/

题目思路

思路: 1.n台计算机连接成一个网络至少要n-1根线缆; 2.n台计算机连接成一个网络,等用于整个网络只有一个连通分量

代码: 1.特判: 已知线缆数目是否小于n-1 2.根据已知线缆connections构建图,求连通分量个数N 3.最少操作次数等同于N-1,即将N个连通分量相连需要N-1根线缆。

code for Python3

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n-1: return -1
        parents = list(range(n))
        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]

        def union(x, y):
            parents[find(y)] = parents[x]

        for x, y in connections:
            root_x, root_y = find(x), find(y)
            if root_x != root_y:
                parents[root_y] = root_x

        return sum([find(x) == x for x in range(n)]) - 1

复杂度分析

QiZhongdd commented 2 years ago

var makeConnected = function (n, connections) {
  // 连接 n 台电脑至少需要 n - 1 根线缆
  if (connections.length < n - 1) {
    return -1;
  }
  // 计算联通分量,最小操作次数就是将联通分量链接的次数
  let father = Array.from({ length: n }, (v, i) => i);
  let count = n;
  for (connection of connections) {
    union(...connection);
  }

  return count - 1;

  function find(v) {
    if (father[v] !== v) {
      father[v] = find(father[v]);
    }
    return father[v];
  }

  function union(x, y) {
    if (find(x) !== find(y)) {
      count--;
      father[find(x)] = find(y);
      // 联通分量数减一
    }
  }
};
fzzfgbw commented 2 years ago

思路

并查集

代码

class Solution{
     public int makeConnected(int n, int[][] connections) {
        if (connections.length < n - 1) {
            return -1;
        }
        UnionFind uf = new UnionFind(n);
        for (int[] connection : connections) {
            uf.union(connection[0], connection[1]);
        }
        return uf.rest>=uf.size - 1?uf.size - 1:-1;

    }

    class UnionFind {
        private int rest = 0;
        private int size;
        private int[] parent;

        public UnionFind(int size) {
            this.size = size;
            this.parent = new int[size];
            for (int i = 0; i < size; i++) {
                parent[i] = i;
            }

        }

        public int find(int i) {
            if (parent[i] != i) {
                parent[i] = find(parent[i]);
            }
            return parent[i];
        }

        public void union(int i, int j) {
            int pi = find(i);
            int pj = find(j);

            if (pi != pj) {
                size--;
                if (pi > pj) {
                    parent[pi] = pj;
                } else {
                    parent[pj] = pi;
                }
            }else{
                rest++;
            }

        }

    }
}

复杂度分析

shixinlovey1314 commented 2 years ago

Title:1319. Number of Operations to Make Network Connected

Question Reference LeetCode

Solution

In order to find out if we could rewire the cables, we need to know how many extra cables do we have. During iteration connections, if two computers have been indirectely connected, we know that the cable between them is an extra cable that we could use to connect other disconnected computers. After found out the number of extra cables, we just need to find out how many set of networks we have, if we have more cables than the seperate networks, we could reroute the cables, thus we return the number of disconnected networks, otherwise, return - 1;

Code

class Solution {
public:
    vector<int> parent;

    int find(int i) {
        int p = parent[i];

        while (p != parent[p])
            p = parent[p];

        return p;
    }

    void union_node(int i, int j) {
        int pi = find(i);
        int pj = find(j);

        if (pi == pj)
            return;
        if (pi < pj)
            parent[pj] = pi;
        else
            parent[pi] = pj;
    }

    int makeConnected(int n, vector<vector<int>>& connections) {
        parent = vector<int>(n);
        // initially, each node's parent is itself
        for (int i = 0; i < n; i++)
            parent[i] = i;

        int n_dup = 0;
        for(vector<int>& conn : connections) {        
            // (x, y) already connected, we can use its cable to connect others.
            if (find(conn[0]) == find(conn[1])) {
                n_dup++;
            } else {
                union_node(conn[0], conn[1]);
            }
        }

        int n_tree = 0;
        set<int> counter;
        for (int i = 0; i < n; i++) {
            int p = find(i);
            if (!counter.count(p)) {
                n_tree++;
                counter.insert(p);
            }
        }

        return n_dup >= n_tree - 1? n_tree - 1 : -1;
    }
};

Complexity

Time Complexity and Explanation

Space Complexity and Explanation

laurallalala commented 2 years ago

代码

class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n-1: return -1
        parents = list(range(n))
        def find(x):
            if parents[x] != x:
                parents[x] = find(parents[x])
            return parents[x]

        def union(x, y):
            parents[find(y)] = parents[x]

        for x, y in connections:
            root_x, root_y = find(x), find(y)
            if root_x != root_y:
                parents[root_y] = root_x

        return sum([find(x) == x for x in range(n)]) - 1

复杂度

falconruo commented 2 years ago

思路: 不同的电脑连接成连通分量(网络),计算连通分量数M, 连接M个网络,需要M-1条线,如果线少于M-1肯定是无法连通的

复杂度分析:

代码(C++):

class DSU {
public:
    vector<int> parent;
    int network;

    DSU(int n) {
        parent.resize(n);

        for (int i = 0; i < n; ++i)
            parent[i] = i;

        network = n;
    }

    int Find(int x) {
        if (x != parent[x]) {
            parent[x] = Find(parent[x]);
        }

        return parent[x];
    }

    void Union(int x, int y) {
        int parentX = Find(x);
        int parentY = Find(y);

        if (parentX != parentY) {
            parent[parentX] = parentY;
            network--;
        }
    }
};
class Solution {
public:
    int makeConnected(int n, vector<vector<int>>& connections) {
        if (n > connections.size() + 1) return -1;
        DSU dsu(n);

        for (auto& c : connections) {
            dsu.Union(c[0], c[1]);
        }

        return dsu.network - 1;
    }
};
zhiyuanpeng commented 2 years ago
class Solution:
    def makeConnected(self, n: int, connections: List[List[int]]) -> int:
        if len(connections) < n - 1:
            return -1
        parent = {}
        def find(x):
            parent.setdefault(x, x)
            if x != parent[x]:
                parent[x] = find(parent[x])  # path compression
            return parent[x]

        def union(x, y):
            rootX = find(x)
            rootY = find(y)
            if rootX == rootY:
                return
            parent[rootX] = rootY

        for a, b in connections:
            union(a, b)

        k = len(set(map(find, range(n)))) - 1 
        return k
chenming-cao commented 2 years ago

解题思路

并查集。根据结论形成一个连通分量所需的最小边数等于顶点数 - 1。先判断能否形成一个连通分量。如果不行返回-1。如果可以,则求现有的连通分量总个数,总个数 - 1即为形成连通分量还需要的边数,即为最后结果。

代码

class Solution {
    class UnionFind {
        int[] parent;

        public UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
        }

        public int find(int i) {
            if (parent[i] != i) {
                parent[i] = find(parent[i]);
            }
            return parent[i];
        }

        public void union(int i1, int i2) {
            int x = find(i1);
            int y = find(i2);
            parent[x] = y;
        }
    }

    public int makeConnected(int n, int[][] connections) {
        int edges = connections.length; // number of edges
        // the minimum number of edges needed to form a connected component is number of nodes - 1
        if (edges < n - 1) return -1;

        UnionFind uf = new UnionFind(n);
        // connect based on edges
        for (int[] connection: connections) {
            uf.union(connection[0], connection[1]);
        }
        // count the number of different connected components
        Set<Integer> roots = new HashSet<>();
        for (int i = 0; i < n; i++) {
            int root = uf.find(i);
            roots.add(root);
        }
        // calculate the number of connected components to union in order to form only one connected component
        return roots.size() - 1;
    }
}

复杂度分析