Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree.

For example:

Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true.

Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false.

Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

This problem can be solved by using union find, reference this blog:https://segmentfault.com/a/1190000003791051

复杂度

时间 O(N^M) 空间 O(N)

思路

判断输入的边是否能构成一个树,我们需要确定两件事:

  1. 这些边是否构成环路,如果有环则不能构成树

  2. 这些边是否能将所有节点连通,如果有不能连通的节点则不能构成树

因为不需要知道具体的树长什么样子,只要知道连通的关系,所以Union Find(并查集)相比深度优先搜索是更好的方法。我们定义一个并查集的数据结构,并提供标准的四个接口:

  • union 将两个节点放入一个集合中

  • find 找到该节点所属的集合编号

  • areConnected 判断两个节点是否是一个集合

  • count 返回该并查集中有多少个独立的集合

具体并查集的原理,参见这篇文章。简单来讲,就是先构建一个数组,节点0到节点n-1,刚开始都各自独立的属于自己的集合。这时集合的编号是节点号。然后,每次union操作时,我们把整个并查集中,所有和第一个节点所属集合号相同的节点的集合号,都改成第二个节点的集合号。这样就将一个集合的节点归属到同一个集合号下了。我们遍历一遍输入,把所有边加入我们的并查集中,加的同时判断是否有环路。最后如果并查集中只有一个集合,则说明可以构建树。

注意

因为要判断是否会产生环路,union方法要返回一个boolean,如果两个节点本来就在一个集合中,就返回假,说明有环路

Union Find based on quick find:  17ms

 public class Solution {
public boolean validTree(int n, int[][] edges) {
unionfind uf = new unionfind(n);
for (int i=0; i<edges.length; i++) {
if (uf.areConnected(edges[i][0], edges[i][1])) return false;
else {
uf.union(edges[i][0], edges[i][1]);
}
}
return uf.count()==1;
} public class unionfind {
int[] ids; //union id for each node
int cnt; //the number of independent union public unionfind(int size) {
this.ids = new int[size];
for (int i=0; i<size; i++) {
ids[i] = i;
}
this.cnt = size;
} public boolean union(int i, int j) {
int src = find(i);
int dst = find(j);
if (src != dst) {
for (int k=0; k<ids.length; k++) {
if (ids[k] == src) {
ids[k] = dst;
}
}
cnt--;
return true;
}
return false;
} public int find(int i) {
return ids[i];
} public boolean areConnected(int i, int j) {
return find(i)==find(j);
} public int count() {
return cnt;
}
}
}

faster: Union Find based on quick union: 3ms

 public class Solution {
public boolean validTree(int n, int[][] edges) {
unionfind uf = new unionfind(n);
for (int i=0; i<edges.length; i++) {
if (uf.areConnected(edges[i][0], edges[i][1])) return false;
else {
uf.union(edges[i][0], edges[i][1]);
}
}
return uf.count()==1;
} public class unionfind {
int[] ids; //union id for each node
int cnt; //the number of independent union public unionfind(int size) {
this.ids = new int[size];
for (int i=0; i<size; i++) {
ids[i] = i;
}
this.cnt = size;
} public void union(int i, int j) {
int rooti = find(i);
int rootj = find(j);
ids[rooti] = rootj;
this.cnt--;
} public int find(int i) {
while (ids[i] != i) i = ids[i];
return i;
} public boolean areConnected(int i, int j) {
return find(i)==find(j);
} public int count() {
return cnt;
}
}
}

Summary:

Dectect cycle in directed graph:

Detect cycle in a directed graph is using a DFS. Depth First Traversal can be used to detect cycle in a Graph. DFS for a connected graph produces a tree. There is a cycle in a graph only if there is a back edge present in the graph. A back edge is an edge that is from a node to itself (selfloop) or one of its ancestor in the tree produced by DFS. In the following graph, there are 3 back edges, marked with cross sign. We can observe that these 3 back edges indicate 3 cycles present in the graph.

To detect a back edge, we can keep track of vertices currently in recursion stack of function for DFS traversal. If we reach a vertex that is already in the recursion stack, then there is a cycle in the tree. The edge that connects current vertex to the vertex in the recursion stack is back edge. We have used recStack[] array to keep track of vertices in the recursion stack.

Detect cycle in undirected graph:

method 1: Union Find  The time complexity of the union-find algorithm is O(ELogV).

method 2: DFS + parent node  Like directed graphs, we can use DFSto detect cycle in an undirected graph in O(V+E) time. We do a DFS traversal of the given graph. For every visited vertex ‘v’, if there is an adjacent ‘u’ such that u is already visited and u is not parent of v, then there is a cycle in graph. If we don’t find such an adjacent for any vertex, we say that there is no cycle. The assumption of this approach is that there are no parallel edges between any two vertices.

Leetcode: Graph Valid Tree && Summary: Detect cycle in undirected graph的更多相关文章

  1. [LeetCode] 261. Graph Valid Tree 图是否是树

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  2. [Locked] Graph Valid Tree

    Graph Valid Tree Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is ...

  3. [LeetCode#261] Graph Valid Tree

    Problem: Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair o ...

  4. [LeetCode] Graph Valid Tree 图验证树

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  5. LeetCode Graph Valid Tree

    原题链接在这里:https://leetcode.com/problems/graph-valid-tree/ 题目: Given n nodes labeled from 0 to n - 1 an ...

  6. [LeetCode] 261. Graph Valid Tree _ Medium tag: BFS

    Given n nodes labeled from 0 to n-1 and a list of undirected edges (each edge is a pair of nodes), w ...

  7. Graph Valid Tree -- LeetCode

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  8. [Swift]LeetCode261.图验证树 $ Graph Valid Tree

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  9. Graph Valid Tree

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

随机推荐

  1. ServletDemo

    1. Servlet 接口 继承 Servlet 接口,实现Servlet 接口的 所有抽象方法! 实现类代码 package xw.servlet; import java.io.IOExcepti ...

  2. (转)投票系统,更改ip刷票

    前言 相信大家平时肯定会收到朋友发来的链接,打开一看,哦,需要投票.投完票后弹出一个页面(恭喜您,您已经投票成功),再次点击的时候发现,啊哈,您的IP(***.***.***.***)已经投过票了,不 ...

  3. iOS 键盘隐藏

     IOS7 点击空白处隐藏键盘的几种方法   IOS开发中经常要用到输入框,默认情况下点击输入框就会弹出键盘,但是必须要实现输入框return的委托方法才能取消键盘的显示,对于用户体验来说很不友好,我 ...

  4. Java HashMap、LinkedHashMap

    如果需要使用的Map中的key无序,选择HashMap:如果要求key有序,则选择TreeMap. 但是选择TreeMap就会有性能问题,因为TreeMap的get操作的时间复杂度是O(log(n)) ...

  5. MVC 中的 ViewModel

    此文章总结自:http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applica ...

  6. 开始了ecshop

    一个多星期前开始接触ecshop,突然决定要用它来做网站,于是从网上找各种手册与视频,联系官网客服,然后知道官网一共提供三种类型的服务,一种是ecshop授权,不包含任何技术支持,第二种是易开店的标准 ...

  7. groovy

    1.加载和卸载(每次都新建一个GroovyClassLoader 实例,然后使用新建的classloader去加载) try { GroovyClassLoader groovyClassLoader ...

  8. SqlServer基础:Bit类型

    SqlServer的bit类是只0或者1,默认不输入值时为null,但是如果输入的值不是0和1时,则默认填充的值为1

  9. 分享一下怎么开发一款图片视频类App,秒拍和prisma

    第一步,分解短视频App的功能 我们在秒拍官网看到如此描述: [视频拍摄及导入]支持直接拍摄及导入手机本地的视频 [照片电影]照片专属特效,轻松创作照片电影 [MV特效]10余款全新MV特效,让普通视 ...

  10. Power-BI For K3 免费版培训与交流!Q群视频培训,绝对干货!

    Power-BI  For K3 免费版培训与交流!Q群视频培训,绝对干货!1.产品安装与配置:2.产品使用:3.个性化开发(现场提需求现场开发):4.交流互动.时间:2015-12-03(周四)晚8 ...