LintCode 590. Connecting Graph II (并查集经典题!!!)

本文介绍了一种使用并查集算法解决图连接和查询问题的方法。通过维护节点的父节点和节点数量,实现高效地连接图中两个节点,并能快速查询包含特定节点的连通组件大小。文章详细解释了算法实现细节,包括路径压缩和组件合并的正确操作。
  1. Connecting Graph II
    Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning.

You need to support the following method:

connect(a, b), an edge to connect node a and node b
query(a), Returns the number of connected component nodes which include node a.
Example
5 // n = 5
query(1) return 1
connect(1, 2)
query(1) return 2
connect(2, 4)
query(1) return 3
connect(1, 4)
query(1) return 3

思路:
经典并查集算法
注意:

  1. 在query()里面必须返回nodeNum[find(a)]而不是nodeNum[father[a]]。原因是当a的component跟另一个component合并时,father[a]可能还没更新。举例如下:
    input case:
    ConnectingGraph2(5)
    query(1)
    connect(1, 2)
    query(1)
    connect(2, 4) – connect(2,4)后,1的father[]还未更新
    query(1) – 如果直接返回nodeSum[father[1]]则出错!!!
    connect(1, 4)
    query(1)

同样,connect()里面也不能用father[a],必须用find(a)。
2) path compression的条件也可以写成while(x2!=father[x2]),但稍慢。
3) connect()里面是father[fatherA]=fatherB,不要写成father[a]=father[b]或father[a]=fatherB之类的。

代码如下:

class ConnectingGraph2 {
public:
    /*
    * @param n: An integer
    */
    ConnectingGraph2(int n) {
        father.resize(n + 1);
        nodeNum.resize(n + 1);
        for (int i = 1; i <= n; ++i) {
            father[i] = i;
            nodeNum[i] = 1;
        }
    }

    /*
     * @param a: An integer
     * @param b: An integer
     * @return: nothing
     */
    void connect(int a, int b) {
        int rootA = find(a);   //不能用father[a]
        int rootB = find(b);   //不能用father[b]
        if (rootA != rootB) {
            father[rootA] = rootB;
            nodeNum[rootB] += nodeNum[rootA];
        }
    }

    /*
     * @param a: An integer
     * @return: An integer
     */
    int query(int a) {
    //    return nodeNum[father[a]];    //wrong!!!
        return nodeNum[find(a)];
    }
    
private:
    vector<int> father;
    vector<int> nodeNum;
    
    //find the root of x
    int find(int x) {
        int x2 = x;
        
        if (father[x] == x) return x;
        
        while(father[x] != x) {
            x = father[x];
        }
        
        //path compression
        while (x2 != x) {
            int temp = father[x2];
            father[x2] = x;
            x2 = temp;
        }
        
        return x;
    }
};
根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值