并查集最佳实践 约定不等于承诺〃 2022-09-04 13:58 190阅读 0赞 ### 并查集 ### 欢迎关注我的公众号 [dying 搁浅][dying] 希望本文对你有所帮助 show the code 几乎所有连通问题,合并问题都可以考虑使用并查集进行优雅求解 /** * @program: dying-stranded * @description: 并查集 * 标准并查集提供两个方法,这两个方法时间复杂度为 O(1) * 合并(union):把两个不相交的集合合并为一个集合。 * 查询是否为同一集合(isSameSet):查询两个元素是否在同一个集合中。 * @author: wangzibin **/ package com.dying.stranded.algorithm.base; import com.google.common.base.Objects; import com.google.common.collect.Maps; import org.apache.commons.collections4.CollectionUtils; import java.util.*; /** * @program: dying-stranded * @description: 并查集 * 标准并查集提供两个方法,这两个方法时间复杂度为 O(1) * 合并(union):把两个不相交的集合合并为一个集合。 * 查询是否为同一集合(isSameSet):查询两个元素是否在同一个集合中。 * @author: wangzibin **/ public class UnionFindSet<T> { static class Node<T> { T value; Node(T t) { value = t; } @Override public boolean equals(Object o) { return this == o; } @Override public int hashCode() { return Objects.hashCode(value); } } /** * 记录所有节点 */ Map<T, Node<T>> nodes; /** * 记录所有节点父节点 */ Map<Node<T>, Node<T>> parents; /** * 记录代表节点集合大小 */ Map<Node<T>, Integer> setSize; public UnionFindSet(Collection<T> collection) { if (CollectionUtils.isEmpty(collection)) { return; } nodes = Maps.newHashMap(); parents = Maps.newHashMap(); setSize = Maps.newHashMap(); for (T item : collection) { Node<T> node = new Node<>(item); nodes.put(item, node); parents.put(node, node); setSize.put(node, 1); } } public void union(T t1, T t2) { Node<T> t1RootNode = findRootNode(t1); Node<T> t2RootNode = findRootNode(t2); if (t1RootNode == null || t2RootNode == null) { return; } if (isSameNode(t1RootNode, t2RootNode)) { return; } Integer t1SetSize = setSize.get(t1RootNode); Integer t2SetSize = setSize.get(t2RootNode); // 小集合挂大集合 优化找 root 节点速度 Node<T> parentNode = t1SetSize > t2SetSize ? t1RootNode : t2RootNode; Node<T> subNode = t1SetSize > t2SetSize ? t2RootNode : t1RootNode; parents.put(subNode, parentNode); setSize.put(parentNode, t1SetSize + t1SetSize); setSize.remove(subNode); } public boolean isSameSet(T t1, T t2) { Node<T> t1RootNode = findRootNode(t1); Node<T> t2RootNode = findRootNode(t2); return isSameNode(t1RootNode, t2RootNode); } public Integer getSetSize() { return setSize.size(); } private boolean isSameNode(Node<T> node1, Node<T> node2) { if (node1 == null || node2 == null) { return false; } return node1.equals(node2); } /** * @Description: 寻找代表节点 * @Param item * @Return: com.dying.stranded.algorithm.base.UnionFindSet.Node<T> * @Author: wangzibin */ private Node<T> findRootNode(T item) { Node<T> current = nodes.get(item); if (current == null) { return null; } Stack<Node<T>> path = new Stack<>(); while (current != parents.get(current)) { path.push(current); current = parents.get(current); } // 这里做优化将查询路径上的所有节点直接指向根,将链扁平化,优化后续查询速度 while (!path.isEmpty()) { parents.put(path.pop(), current); } return current; } } ### Leecode 例题 [547. 省份数量][547.] ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3c5MDMzMjg2MTU_size_16_color_FFFFFF_t_70] 直接给出 AC 代码: import java.util.*; /** * @program: dying-stranded * @description: * @author: wangzibin **/ public class Solution { public static int findCircleNum(int[][] isConnected) { List<Integer> items = new ArrayList<>(); for (int i = 0; i < isConnected.length; i++) { items.add(i); } UnionFindSet<Integer> unionFindSet = new UnionFindSet<>(items); for (int i = 0; i < isConnected.length; i++) { for (int j = 0; j < isConnected[i].length; j++) { if (isConnected[i][j] == 1) { unionFindSet.union(i, j); } } } return unionFindSet.getSetSize(); } static class UnionFindSet<T> { static class Node<T> { T value; Node(T t) { value = t; } @Override public boolean equals(Object o) { return this == o; } @Override public int hashCode() { return Objects.hashCode(value); } } /** * 记录所有节点 */ Map<T, Node<T>> nodes; /** * 记录所有节点父节点 */ Map<Node<T>, Node<T>> parents; /** * 记录代表节点集合大小 */ Map<Node<T>, Integer> setSize; public UnionFindSet(Collection<T> collection) { if (collection==null||collection.isEmpty()) { return; } nodes = new HashMap<>(); parents = new HashMap<>(); setSize = new HashMap<>(); for (T item : collection) { Node<T> node = new Node<>(item); nodes.put(item, node); parents.put(node, node); setSize.put(node, 1); } } public void union(T t1, T t2) { Node<T> t1RootNode = findRootNode(t1); Node<T> t2RootNode = findRootNode(t2); if (t1RootNode == null || t2RootNode == null) { return; } if (isSameNode(t1RootNode, t2RootNode)) { return; } Integer t1SetSize = setSize.get(t1RootNode); Integer t2SetSize = setSize.get(t2RootNode); // 小集合挂大集合 优化找 root 节点速度 Node<T> parentNode = t1SetSize > t2SetSize ? t1RootNode : t2RootNode; Node<T> subNode = t1SetSize > t2SetSize ? t2RootNode : t1RootNode; parents.put(subNode, parentNode); setSize.put(parentNode, t1SetSize + t1SetSize); setSize.remove(subNode); } public boolean isSameSet(T t1, T t2) { Node<T> t1RootNode = findRootNode(t1); Node<T> t2RootNode = findRootNode(t2); return isSameNode(t1RootNode, t2RootNode); } public Integer getSetSize() { return setSize.size(); } private boolean isSameNode(Node<T> node1, Node<T> node2) { if (node1 == null || node2 == null) { return false; } return node1.equals(node2); } /** * @Description: 寻找代表节点 * @Param item * @Return: Node<T> * @Author: wangzibin */ private Node<T> findRootNode(T item) { Node<T> current = nodes.get(item); if (current == null) { return null; } Stack<Node<T>> path = new Stack<>(); while (current != parents.get(current)) { path.push(current); current = parents.get(current); } // 这里做优化将查询路径上的所有节点直接指向根,将链扁平化,优化后续查询速度 while (!path.isEmpty()) { parents.put(path.pop(), current); } return current; } } } 最后分享一个很有意思的网站: [深海][Link 1] [dying]: https://mp.weixin.qq.com/s/9n-F1jPMfmOK6uW_LXqOHQ [547.]: https://leetcode-cn.com/problems/number-of-provinces/ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3c5MDMzMjg2MTU_size_16_color_FFFFFF_t_70]: /images/20220829/1ab414cdca1d46309ad75982a4d0263e.png [Link 1]: https://neal.fun/deep-sea/
相关 并查集最佳实践 并查集 欢迎关注我的公众号 [dying 搁浅][dying] 希望本文对你有所帮助 show the code 几乎所有连通问题,合并问题都可以考虑使用并查集进行优雅 约定不等于承诺〃/ 2022年09月04日 13:58/ 0 赞/ 191 阅读
相关 并查集 Ⅱ \[poj 1611\] ([http://poj.org/problem?id=1611][http_poj.org_problem_id_1611]) 题目描述: T 古城微笑少年丶/ 2022年08月03日 14:35/ 0 赞/ 278 阅读
相关 并查集 并查集JAVA版框架 并查集是一种用来管理元素分组情况的数据结构。 并查集可以高效地进行如下操作: \--查询元素a和元素b是否属于同一组 落日映苍穹つ/ 2022年06月16日 12:44/ 0 赞/ 314 阅读
相关 并查集 这个文章是几年前水acm的时候转的, 当时也不知道作者是谁, 要是有人知道的话说一下吧 并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了。以前我无法解决的 港控/mmm°/ 2022年06月13日 14:13/ 0 赞/ 300 阅读
相关 并查集 > 题目 > 某学校近期要组织全校同学出去参加某项活动,由于人数众多,学校决定让同学们自行组队,以小组为单位进行活动。假设学校一共n个同学,每个同学有一个唯一的数字作为标签 Myth丶恋晨/ 2022年06月08日 09:24/ 0 赞/ 308 阅读
相关 并查集 森林: 森林是由若干棵互不相交的树组成,两棵树分别独立,没有交集 ![20181112082744488.png][] 并查集: 并查集的结构和森林十分相似,是 Love The Way You Lie/ 2022年04月17日 02:27/ 0 赞/ 367 阅读
相关 并查集 来看一个实例,[杭电1232畅通工程][1232] 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性 我就是我/ 2022年03月29日 10:58/ 0 赞/ 370 阅读
相关 并查集 例题: ![输入样例][20190805122001677.png] 输入样例,第一行为一个整数n,代表有n台电脑,编号1-n;接下来进行一系列操作,当输入‘c’时,判 Dear 丶/ 2021年11月11日 08:04/ 0 赞/ 387 阅读
相关 并查集 一、算法解释 用于解决一些有N个元素的集合应用问题。 1、将每个元素初始化为自身单独成为一个集合。用p\[i\]的值表示该元素所在集合。 ![这里写图片描述][S 桃扇骨/ 2021年09月14日 02:56/ 0 赞/ 474 阅读
相关 并查集 并查集的作用就是快速判断两个元素是否在同一个集合中,快速将两个集合合并 基本模板 include <iostream> include <a 比眉伴天荒/ 2021年06月22日 15:37/ 0 赞/ 572 阅读
还没有评论,来说两句吧...