【力扣刷题】3-连通网络的操作次数(并查集)

题目

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

示例

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

1.了解并查集

1.1定义:

在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。有一个联合-查找算法(Union-find Algorithm)定义了两个用于此数据结构的操作:

Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。
由于支持这两种操作,一个不相交集也常被称为联合-查找数据结构(Union-find Data Structure)或合并-查找集合(Merge-find Set)。
为了更加精确的定义这些方法,需要定义如何表示集合。一种常用的策略是为每个集合选定一个固定的元素,称为代表,以表示整个集合。接着,Find(x)Find(x) 返回 xx 所属集合的代表,而 Union 使用两个集合的代表作为参数。

1.2适用范围:

经常用来解决集合相关的问题:

  1. 查询节点属于的组
  2. 判断两个节点是否属于同一个组
  3. 连接两个节点,使之属于同一个组
  4. 获取组的数目
1.3经典模板:

三个常用的函数:1.初始化前项节点;2.寻找父节点;3.合并集合;


        //寻找子节点  与  路径压缩
        int find_point(int root) {
            int  tmp;
            int son = root;
            while (pre[root] != root) {//找到根节点root
                root = pre[root];
            }
            while (root != son) {   //进行路径的压缩
                tmp = pre[son];
                pre[son] = root;
                son = tmp;
            }
            return root;
        }

        //合并集合
        void join(int m1, int m2) {
            int x, y;
            x = find_point(m1);
            y = find_point(m2);
            if (x != y) {
                pre[x] = y;
                jion_num--;
            }else{
                repetition_num++;
            }
        }
        //初始化前项节点
            for(int i=0;i<=n;i++){
                pre[i]=i;
            }
           
1.4解题思路:

如果要深入了解并查集可在该博客进行生动的学习,这个博客用生动的语言对原理表达的淋漓尽致。我最后总结了一些:根据题目意思:将输入的链路信息进行更新集合操作,合并二个集合的时候会有那个集合的父节点成为新的父结点可根据题目的优先级别限制进行改写。对于计算集合数可中二个集合合并会减少一个集合入手。通常集合类的问题会用到并查集的方法,该题的代码如下:

class Solution {
private:
        vector<int> pre;
        int jion_num = 0;
        int repetition_num=0;
        //寻找子节点  与  路径压缩
public:
        int find_point(int root) {
            int  tmp;
            int son = root;
            while (pre[root] != root) {//找到根节点root
                root = pre[root];
            }
            while (root != son) {   //进行路径的压缩
                tmp = pre[son];
                pre[son] = root;
                son = tmp;
            }
            return root;
        }

        //加入集合
        void join(int m1, int m2) {
            int x, y;
            x = find_point(m1);
            y = find_point(m2);
            if (x != y) {
                pre[x] = y;
                jion_num--;
            }else{
                repetition_num++;
            }
        }

        int makeConnected(int n, vector<vector<int>>& connections) {
            jion_num=n;
            //初始化前项节点
            pre.resize(n+10);
            for(int i=0;i<=n+5;i++){
                pre[i]=i;
            }
            for(int i=0;i<connections.size();i++){
                join(connections[i][0],connections[i][1]);
            }
            return (repetition_num>=jion_num-1)?jion_num-1:-1;
        }  
    
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值