算法之并查集整理

力扣题解990.等式方程的可满足性

思路:由于相等关系具有传递性,所有相等的变量属于同一个集合;只关心连通情况,不关心距离,因此很容易想到并查集。

设计算法流程:

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

并查集(union-find algorithm,Disjoint Sets):

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

每个节点都保存了到节点的引用

        并查集的优化:路径压缩(Path Compression)与按“秩(rank)”合并

        路径压缩是指在查询的过程中,更改节点的指向,使得树的高度更低,一般而言,有“隔代压缩”和“完全压缩”两种策略。

        按秩合并是指在合并的过程中,使得“高度”更低 的树的根结点指向高度更高的根结点,以避免合并以后的树高度增加

        路径压缩和按秩合并一起使用的时候,难以维护“秩”准确的定义,但依然具有参考价值。

        并查集同时使用“路径压缩”和“按秩合并”,“合并”与“查询”的时间复杂度接近O(1);

public class UnionFind {
   private int[] parent;

   public UnionFind(int n) {
      parent = new int[n];
      for (int i = 0; i < n; i++) {  //每个节点赋值给自已,表示每个节点是单独的集合
         parent[i] = i;
      }
   }

   /**
    *
    * @param x
    * @return 返回根节点
    */
   public int find(int x) {
      while (x != parent[x]) {
         parent[x] = parent[parent[x]]; //路径压缩
         x = parent[x];
      }
      return x;
   }

   /**
    * 如果合并成功,返回true
    * @param x
    * @param y
    */
   public void union(int x, int y) {
      int rootX = find(x);
      int rootY = find(y);
      parent[rootX] = rootY;
   }

   public boolean isConnected(int x, int y) {
      return find(x) == find(y) ;
   }
}

力扣中并查集相关的题目:

  • 547:朋友圈
  • 200:岛屿数量
  • 684:冗余连接
  • 1319:连通网络的操作次数
  • 399:除法求值
  • 952:按公因数计算最大组件大小
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值