代码随想录训练营第五十五天| 并查集理论基础 107 寻找存在的路径

最重要的问题是 什么是并查集 为什么要用并查集 怎么用 怎么优化?

 讲解链接:并查集理论基础 | 代码随想录

只听过并查集 但是从来不理解他做什么 最近学了集合的内容有点感触了 

并查集(Disjoint Set Union,DSU) 是一种用于管理元素分组的数据结构,主要支持以下两种操作:

  1. 查找(Find):确定某个元素属于哪个集合(通常返回集合的代表元素)。

  2. 合并(Union):将两个集合合并为一个集合。


核心思想:

  • 每个集合用一棵树表示,树的根节点是集合的代表元素。

  • 通过路径压缩和按秩合并优化,使操作的时间复杂度接近常数。

并查集最基础的路径压缩模版(java)

public class UnionFind {
    private int[] father; // 父节点数组

    // 初始化并查集
    public UnionFind(int n) {
        father = new int[n];
        for (int i = 0; i < n; i++) {
            father[i] = i; // 每个元素的父节点初始指向自己
        }
    }

    // 查找(带路径压缩)
    public int find(int u) {
        return u == father[u] ? u : (father[u] = find(father[u])); // 路径压缩
    }

    // 判断 u 和 v 是否属于同一个集合
    public boolean isSame(int u, int v) {
        u = find(u);
        v = find(v);
        return u == v;
    }

    // 合并 u 和 v 所在的集合
    public void join(int u, int v) {
        u = find(u); // 找到 u 的根
        v = find(v); // 找到 v 的根
        if (u == v) return; // 如果根相同,说明已经在同一个集合,直接返回
        father[v] = u; // 将 v 的根指向 u 的根
    }
}

按秩合并模版 

public class UnionFind {
    private int[] father; // 父节点数组
    private int[] rank;   // 树的秩(深度)

    // 初始化并查集
    public UnionFind(int n) {
        father = new int[n];
        rank = new int[n];
        for (int i = 0; i < n; i++) {
            father[i] = i; // 每个元素的父节点初始指向自己
            rank[i] = 1;   // 初始深度为 1
        }
    }

    // 查找(带路径压缩)
    public int find(int u) {
        return u == father[u] ? u : (father[u] = find(father[u])); // 路径压缩
    }

    // 判断 u 和 v 是否属于同一个集合
    public boolean isSame(int u, int v) {
        u = find(u);
        v = find(v);
        return u == v;
    }

    // 合并 u 和 v 所在的集合(带按秩合并)
    public void join(int u, int v) {
        u = find(u); // 找到 u 的根
        v = find(v); // 找到 v 的根
        if (u == v) return; // 如果根相同,说明已经在同一个集合,直接返回

        // 按秩合并
        if (rank[u] > rank[v]) {
            father[v] = u;
        } else if (rank[u] < rank[v]) {
            father[u] = v;
        } else {
            father[v] = u;
            rank[u]++;
        }
    }
}

并查集可以解决什么问题呢?

主要就是集合问题,两个节点在不在一个集合,也可以将两个节点添加到一个集合中

107. 寻找存在的路径 

题目链接:卡码网题目链接(ACM模式) (opens new window)

讲解链接:代码随想录

import java.util.Scanner;

public class Carlcode107 {
    //并查集模版
    static class DisJoint{
        private int[] father;

        public DisJoint(int n){
            father = new int[n];//初始化 father 数组,大小为 n。
            for (int i = 0; i < n; i++) {
                father[i] = i;
            }
        }
        // 查找
        public int find(int n){
            //如果 n 的父节点是它自己(即 n == father[n]),
            //说明 n 是根节点,直接返回 n
            //否则,递归查找 father[n] 的根节点,并通过路径压缩优化,
            //将 n 的父节点直接指向根节点(father[n] = find(father[n]))。
            return n == father[n] ? n : (father[n] = find(father[n]));
        }
        //合并
        public void join(int n, int m){
            n = find(n);//首先,通过 find 方法找到 n 和 m 的根节点。
            m = find(m);
            if(n == m) return;
            //如果n和m的根节点相同 说明它们已经在同一个集合中,直接返回。
            father[m] = n;
            //否则 将m的根节点指向n的根节点(father[m] = n)
        }

        public boolean isSame(int n, int m){
            n = find(n);
            //isSame 方法用于判断节点 n 和 m 是否属于同一个集合。
            m = find(m);
            //通过 find 方法找到 n 和 m 的根节点。
            return n == m;
        }
    }

    public static void main(String[] args) {
        int n, m;
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        DisJoint disJoint = new DisJoint(n + 1);
        //合并到一个集合里(这用的数组)
        for (int i = 0; i < m; i++) {
            disJoint.join(scanner.nextInt(),scanner.nextInt());
        }
        if(disJoint.isSame(scanner.nextInt(), scanner.nextInt())){
            System.out.println(1);
        }else{
            System.out.println(0);
        }
    }
}

打卡打卡 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值