并查集(QuickUnion)

基础代码实现:

find:路径压缩

union:按秩合并

java 复制代码
/**
 * Quick Union 并查集(带按秩合并和路径压缩优化)
 * 两种操作均近似 O(α(n)),α(n) 为反阿克曼函数,效率极高
 */
public class OptimizedUnionFind {
    private int[] parent;   // parent[i] 表示 i 的父节点
    private int[] rank;     // rank[i] 表示以 i 为根的树的高度(秩)
    private int count;      // 连通分量数量

    public OptimizedUnionFind(int n) {
        count = n;
        parent = new int[n];
        rank = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;   // 初始时每个节点指向自己
            rank[i] = 0;     // 树高为 0
        }
    }

    // 查找元素 p 的根节点(带路径压缩)
    public int find(int p) {
        validate(p);
        while (p != parent[p]) {
            // 路径压缩:将 p 的父节点直接设为祖父节点
            parent[p] = parent[parent[p]];
            p = parent[p];
        }
        return p;
        // 递归写法(更简洁,但可能栈溢出):
        // if (p != parent[p]) parent[p] = find(parent[p]);
        // return parent[p];
    }

    // 判断 p 和 q 是否连通
    public boolean connected(int p, int q) {
        return find(p) == find(q);
    }

    // 合并 p 和 q 所在的集合(按秩合并)
    public void union(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);
        if (rootP == rootQ) return;

        // 将秩小的树合并到秩大的树上
        if (rank[rootP] < rank[rootQ]) {
            parent[rootP] = rootQ;
        } else if (rank[rootP] > rank[rootQ]) {
            parent[rootQ] = rootP;
        } else {
            parent[rootQ] = rootP;
            rank[rootP]++;   // 两棵树秩相同,合并后新根秩加 1
        }
        count--;
    }

    // 返回当前连通分量个数
    public int count() {
        return count;
    }

    private void validate(int p) {
        int n = parent.length;
        if (p < 0 || p >= n) {
            throw new IllegalArgumentException("索引 " + p + " 不合法");
        }
    }
}

力扣题:

🗺️ LeetCode 并查集题目推荐路线

难度 题目 题号 说明
入门 岛屿数量 200 最经典的入门题,非常适合第一次接触并查集。
省份数量 547 另一种表述的连通分量问题,和"朋友圈"是同一类。
冗余连接 684 判断图中哪条附加的边会导致环的产生。
等式方程的可满足性 990 将并查集应用到非图论的抽象关系判定中。
最长连续序列 128 并查集也可以用来处理数组元素间的连通性问题。
进阶 被围绕的区域 130 可以结合DFS/BFS和并查集思维解决。
账户合并 721 合并多个账户,可以练习如何将复杂问题抽象为连通性问题。
情侣牵手 765 一个很有意思的题目,考验如何利用并查集解决排列问题。
交换字符串中的元素 1202 结合并查集与排序的字符串处理题。
水位上升的泳池中游泳 778 并查集结合二分查找或排序的经典题目。
打砖块 803 并查集的逆向思维应用(较难)。
实战 最小生成树 (Kruskal) 1584, 1135 Kruskal算法需要依靠并查集来判断是否产生环。
离线查询 处理询问"在某个时间点后,两点是否连通"的动态问题,是并查集的高级应用。

自我感悟总结:

并查集的parent数组的索引是元素域,例如990题就是26个字母,parent=new int[26],

对于parent的定义这里的关键是确定parent=new int[n]的n的大小,具体看题目的意思。

rank同理是同一个n,表示节点的秩,也就是树高

count是连通分量,可以一开始定义为count=n;后面每进行一次union就进行count-- ,例如n=5,有五个元素分别为1-5,count=5,union 1,2 2,3 3,4 4,5,union了四次,count=1,也就是连通整体的个数是1,具体可以看200岛屿数量这一题。

而128题并不需要连通分量,要的是每一个分量的元素个数的最大值,此时union可以是int类型的返回值,返回祖父节点的连接的元素个数size[root]。

相关推荐
SamDeepThinking2 小时前
适合中小型企业的出口入口网关微服务
java·后端·架构
leo__5202 小时前
基于时延的麦克风声源定位 - C实现
c语言·开发语言·算法
攻防_SRC2 小时前
面向分组密码差分故障分析的属性推导与验证平台
人工智能·算法·机器学习
likerhood2 小时前
Java实现选择题选项乱序算法
java·开发语言·算法
我登哥MVP2 小时前
【SpringMVC笔记】 - 11 - SpringMVC 执行流程
java·spring boot·笔记·spring·tomcat·intellij-idea
小鱼~~2 小时前
最小二乘&均方误差MSE&平均绝对误差MAE
python·算法·机器学习
数智化精益手记局2 小时前
仓库安灯管理系统的异常响应机制:破解仓库安灯管理系统的跨部门协同难题
大数据·数据结构·人工智能·制造·精益工程
田梓燊2 小时前
力扣:138.随机链表的复制
算法·leetcode·链表
笨蛋不要掉眼泪2 小时前
面试篇-java基础上
java·后端·面试·职场和发展