From df9116647912d3a84ced39794a85384f100ba8bc Mon Sep 17 00:00:00 2001 From: LEO D PEN <33611404+LEODPEN@users.noreply.github.com> Date: Wed, 11 Nov 2020 21:25:36 +0800 Subject: [PATCH] =?UTF-8?q?leodpen=20Union-Find=E7=AE=97=E6=B3=95?= =?UTF-8?q?=E5=BA=94=E7=94=A8.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 算法思维系列/UnionFind算法应用.md | 78 ++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/算法思维系列/UnionFind算法应用.md b/算法思维系列/UnionFind算法应用.md index fef484a..c1af151 100644 --- a/算法思维系列/UnionFind算法应用.md +++ b/算法思维系列/UnionFind算法应用.md @@ -20,6 +20,8 @@ [990.等式方程的可满足性](https://leetcode-cn.com/problems/surrounded-regions) +[261.以图判树](https://leetcode-cn.com/problems/graph-valid-tree/) + **-----------** 上篇文章很多读者对于 Union-Find 算法的应用表示很感兴趣,这篇文章就拿几道 LeetCode 题目来讲讲这个算法的巧妙用法。 @@ -250,4 +252,78 @@ boolean equationsPossible(String[] equations) {

-======其他语言代码====== \ No newline at end of file +======其他语言代码====== + +第261题的Java代码(提供:[LEODPEN](https://github.com/LEODPEN)) + +```java +class Solution { + + class DisjointSet { + + int count; // 连通分量的总个数 + int[] parent; // 每个节点的头节点(不一定是连通分量的最终头节点) + int[] size; // 每个连通分量的大小 + + public DisjointSet(int n) { + parent = new int[n]; + size = new int[n]; + // 初为n个连通分量,期望最后为1 + count = n; + for (int i = 0; i < n; i++) { + // 初始的连通分量只有该节点本身 + parent[i] = i; + size[i] = 1; + } + } + + /** + * @param first 节点1 + * @param second 节点2 + * @return 未连通 && 连通成功 + */ + public boolean union(int first, int second) { + // 分别找到包含first 和 second 的最终根节点 + int firstParent = findRootParent(first), secondParent = findRootParent(second); + // 相等说明已经处于一个连通分量,即说明有环 + if (firstParent == secondParent) return false; + // 将较小的连通分量融入较大的连通分量 + if (size[firstParent] >= size[secondParent]) { + parent[secondParent] = firstParent; + size[firstParent] += size[secondParent]; + } else { + parent[firstParent] = secondParent; + size[secondParent] += size[firstParent]; + } + // 连通分量已合并,count减少 + count--; + return true; + } + + /** + * @param node 某节点 + * @return 包含该节点的连通分量的最终根节点 + */ + private int findRootParent(int node) { + while (node != parent[node]) { + // 压缩路径 + parent[node] = parent[parent[node]]; + node = parent[node]; + } + return node; + } + } + + public boolean validTree(int n, int[][] edges) { + // 树的特性:节点数 = 边数 + 1 + if (edges.length != n - 1) return false; + graph_261.Solution.DisjointSet djs = new graph_261.Solution.DisjointSet(n); + for (int[] edg : edges) { + // 判断连通情况(如果合并的两个点在一个连通分量里,说明有环) + if (!djs.union(edg[0], edg[1])) return false; + } + // 是否全部节点均已相连 + return djs.count == 1; + } +} +```