当前位置: 首页 > article >正文

leetcode - 684. 冗余连接

684. 冗余连接

解决思路

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

并查集

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

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

并查集代码例子

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)

/**
 * 使用 并查集的 方法【参考官方】
 * 执行用时分布 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]);
}


http://www.kler.cn/a/374293.html

相关文章:

  • 自动化运维
  • 「虚拟现实中的心理咨询:探索心灵世界的新方法」
  • PFC前端电路 -- EMI电路
  • c语言水仙花,超简单讲解
  • C++学习笔记3——存储持续性、作用域和链接性
  • 正则表达式(Regular Expressions)
  • 硅谷甄选(11)角色管理
  • Axure文本框读取和赋值高级交互
  • 计算机毕业设计PySpark+大模型 bilibili弹幕情感分析 B站视频数据可视化 B站爬虫 机器学习 深度学习 NLP自然语言处理 大数据毕业设计
  • 技术分享 | 大语言模型增强灰盒模糊测试技术探索
  • SMO算法 公式推导
  • 由 GPT 引发的这波「大模型热」将会如何洗牌?
  • 直接内存、死锁、方法句柄
  • 51单片机ALE引脚的作用 - 锁存地址和输出时钟信号并不冲突
  • 大数据-202 数据挖掘 机器学习理论 - 决策树 sklearn 绘制决策树 防止过拟合
  • 在Mac下安装时间序列软件Hector
  • CodeFuse IDE 0.6 版本发布,支持编辑器诊断问题 AI 修复
  • 网上摄影工作室:Spring Boot框架的应用实例
  • @2025考研er,网上确认在即,西电考点(6113)这些问题你必须知道!
  • 【数据库】SQLite DB Browser有关图书商城的增删改查语句笔记
  • apache druid整合hadoop3.3
  • Discourse 是否支持手机注册
  • 页面内Tab切换-工程问题
  • iptables限制docker端口禁止某台主机访问(使用DOCKER链和raw表的PREROUTING链)
  • ubuntu用户账号相关操作
  • SpringBoot节奏:Web音乐网站构建手册