leetcode - 684. 冗余连接

684. 冗余连接

解决思路

大致上的思路就是将元素加入到 并查集 中,那么在遍历到边的时候先去判断的边的两个端点的 根节点 是否相等,如果相等,那么就代表此刻把这条边加上去就形成了环【可以这么理解,如果形成了环,那么两个端点在环内从那个端点出发都可以到达环内所有节点,只是这里提取出共同的 根节点罢了】

并查集

并查集(Union Find):一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。不交集指的是一系列没有重复元素的集合。

  • 合并(Union):将两个集合合并成一个集合。
  • 查找(Find):确定某个元素属于哪个集合。通常是返回集合内的一个「代表元素」。

并查集代码例子

java 复制代码
public class UnionFind {

    public static class Element<V> {
        public V value;

        public Element(V value) {
            this.value = value;
        }
    }

    public static class UnionFindSet<V> {
        public HashMap<V, Element<V>> elementMap;
        // key: 某个元素,value: 该元素的父
        public HashMap<Element<V>, Element<V>> fatherMap;
        // key: 某个集合的代表元素,value: 该集合的大小
        public HashMap<Element<V>, Integer> sizeMap;

        public UnionFindSet(List<V> list) {
            elementMap = new HashMap<>();
            fatherMap = new HashMap<>();
            sizeMap = new HashMap<>();
            for (V value : list) {
                Element<V> element = new Element<>(value);
                elementMap.put(value, element);
                // 初始化都是自己指向自己,也就是代表元素
                fatherMap.put(element, element);
                sizeMap.put(element, 1);
            }
        }

        /**
         * 给定一个 element,往上一直找,把代表元素(fatherMap 指向自己的为代表元素)返回
         * @param element
         * @return
         */
        public Element<V> findHead(Element<V> element) {
            Stack<Element<V>> path = new Stack<>();
            // 查找代表元素
            while (element != fatherMap.get(element)) {
                path.push(element);
                element = fatherMap.get(element);
            }
            while (!path.isEmpty()) {
                // 将路径上的 element,直接指向 代表元素,加快下次的查找速度
                fatherMap.put(path.pop(), element);
            }
            return element;
        }


        /**
         * 判断是不是在同一个集合
         * @return
         */
        public boolean isSameSet(V a, V b) {
            if (elementMap.containsKey(a) && elementMap.containsKey(b)) {
                return findHead(elementMap.get(a)) == findHead(elementMap.get(b));
            }
            return false;
        }

        /**
         * 将两个集合合并,小的集合加入大的集合中
         * @param a
         * @param b
         */
        public void union(V a, V b) {
            if (elementMap.containsKey(a) && elementMap.containsKey(b)) {
                Element aF = findHead(elementMap.get(a));
                Element bF = findHead(elementMap.get(b));
                if (aF != bF) {
                    Element<V> big = sizeMap.get(aF) >= sizeMap.get(bF) ? aF : bF;
                    Element<V> small = big == aF ? bF : aF;
                    fatherMap.put(small, big);
                    sizeMap.put(big, sizeMap.get(aF) + sizeMap.get(bF));
                    // 不是代表元素了,所以删除掉
                    sizeMap.remove(small);
                }
            }
        }
    }

}

解决

参考链接:. - 力扣(LeetCode)

java 复制代码
/**
 * 使用 并查集的 方法【参考官方】
 * 执行用时分布 1 ms 击败 62.07% 复杂度分析 消耗内存分布 42.10 MB 击败 61.45%
 * @param edges
 * @return
 */
public int[] findRedundantConnection(int[][] edges) {
    int[] parent = new int[edges.length + 1];
    // 初始化,将所有的节点指向自己
    for (int i = 0; i < parent.length; i++) {
        parent[i] = i;
    }
    for (int[] edge : edges) {
        int node1 = edge[0];
        int node2 = edge[1];
        // 如果父节点一样,代表已经形成环了
        if (findHead(parent, node1) == findHead(parent, node2)){
            return edge;
        }
        union(parent, edge);
    }
    return new int[0];
}

/**
 * 查找 根节点,并将 递归路径上的 节点都指向 根节点
 */
public int findHead(int[] parent, int element){
    if (parent[element] != element){
        // 递归获取根节点
        parent[element] = findHead(parent, parent[element]);
    }
    return parent[element];
}

/**
* 将数据加入到  并查集
*/
public void union(int[] parent, int[] edge){
  // 只是一个方向性的问题
  // 就是获取到 端点 0 的根节点,然后将它指向 端点 1 的根节点
  // 这种做法是为了直接指向根节点,如果是直接指向,会造成不是指向自己的根节点
  parent[findHead(parent, edge[0])] = findHead(parent, edge[1]);
}
相关推荐
我真的是大笨蛋3 小时前
K8S-Pod(下)
java·笔记·云原生·容器·kubernetes
碳水加碳水3 小时前
Java代码审计实战:XML外部实体注入(XXE)深度解析
java·安全·web安全·代码审计
纪元A梦3 小时前
贪心算法应用:化工反应器调度问题详解
算法·贪心算法
深圳市快瞳科技有限公司4 小时前
小场景大市场:猫狗识别算法在宠物智能设备中的应用
算法·计算机视觉·宠物
liulilittle4 小时前
OPENPPP2 —— IP标准校验和算法深度剖析:从原理到SSE2优化实现
网络·c++·网络协议·tcp/ip·算法·ip·通信
努力也学不会java4 小时前
【设计模式】 原型模式
java·设计模式·原型模式
方渐鸿5 小时前
【2024】k8s集群 图文详细 部署安装使用(两万字)
java·运维·容器·kubernetes·k8s·运维开发·持续部署
学亮编程手记5 小时前
K8S v1.33 版本主要新特性介绍
java·容器·kubernetes
Haven-6 小时前
Java-面试八股文-JVM篇
java·jvm·面试
我真的是大笨蛋6 小时前
JVM调优总结
java·jvm·数据库·redis·缓存·性能优化·系统架构