数据结构学习之并查集

9 篇文章 0 订阅

“并查集”是一种常见的数据结构,在互联网大厂的笔试题中也能看到它的身影。在刷LeetCode每日一题过程中,发现这种数据结构的妙处,参考LeetCode官方题解,写了这篇博文,供各位小伙伴们学习使用。

并查集的相关知识

  • 并查集用于判断一对元素是否相连,它们的关系是动态添加的,这一类问题叫做【动态连通性】问题;
  • 支持【合并】与【查询是否在同一集合】的操作;
  • 底层结构为【数组】或者【哈希表】,用于表示【结点】指向【父结点】,初始化时指向自己;
  • 【合并】就是把一个集合的根结点指向另一个集合带的根结点,只要根结点一样,就表示在同一个集合里。
  • 这种表示【不相交集合】的方法称之为【代表元法】,以每个结点的根结点作为一个集合的【代表元】。

并查集的相关应用

  • 最小生产树
  • kruskal算法

并查集的优化-路径压缩(隔代压缩)
只要在原始代码的基础上加上下面的代码:

parent[x]=parent[parent[x]];

在这里插入图片描述

并查集的优化-路径压缩(完全压缩)
需要借助递归方法
在这里插入图片描述

并查集的优化-按秩合并

  • 按秩合并是指在合并时,使得【高度】更低树的根结点指向【高度】更高树的根结点,避免合并后的树高度增加;
  • 【路径压缩】和【按秩合并】一起使用时,难以维护秩的准确定义,但依然具有一定的参考价值。

LeetCode990题目如下:
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。

只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。

示例 1:
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。

示例 2:
输出:[“ba","ab”]
输入:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。

示例 3:
输入:[“ab","bc”,“a==c”]
输出:true

示例 4:
输入:[“ab",“b!=c”,"ca”]
输出:false

示例 5:
输入:[“cc","bd”,“x!=z”]
输出:true

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/satisfiability-of-equality-equations

思路:

  • 由于相等关系具有传递性,所有相等的变量属于同一个集合;
  • 只关心连通性,不关心具体节点之间的距离,因此可以使用并查集这种数据结构。

算法设计流程

  • 扫描所有等式,将等式两边1的顶点进行合并;
  • 再扫描所有不等式,检查每一个不等式的两个顶点是不是在一个连通分量里面;
  • 如果在,返回false,表示等式方程有矛盾;
  • 否则,返回true。

Java题解代码如下:

class Solution {
    public static void main(String[] args) {
        String[] equations={"a==b","b!=c","a==c"};
        System.out.println(equationsPossible(equations));
    }
    public static boolean equationsPossible(String[] equations) {
        int length = equations.length;
        int[] parent = new int[26];
        for (int i = 0; i < 26; i++) {
            parent[i] = i;
        }
        for (String str : equations) {
            if (str.charAt(1) == '=') {
                int index1 = str.charAt(0) - 'a';
                int index2 = str.charAt(3) - 'a';
                union(parent, index1, index2);
            }
        }
        for (String str : equations) {
            if (str.charAt(1) == '!') {
                int index1 = str.charAt(0) - 'a';
                int index2 = str.charAt(3) - 'a';
                if (find(parent, index1) == find(parent, index2)) {
                    return false;
                }
            }
        }
        return true;
    }

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

    public static int find(int[] parent, int index) {
        while (parent[index] != index) {
            parent[index] = parent[parent[index]];
            index = parent[index];
        }
        return index;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值