Leetcode: Graph Valid Tree && Summary: Detect cycle in undirected graph
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)
思路
判断输入的边是否能构成一个树,我们需要确定两件事:
这些边是否构成环路,如果有环则不能构成树
这些边是否能将所有节点连通,如果有不能连通的节点则不能构成树
因为不需要知道具体的树长什么样子,只要知道连通的关系,所以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的更多相关文章
- [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), ...
- [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 ...
- [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 ...
- [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), ...
- LeetCode Graph Valid Tree
原题链接在这里:https://leetcode.com/problems/graph-valid-tree/ 题目: Given n nodes labeled from 0 to n - 1 an ...
- [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 ...
- 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), ...
- [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), ...
- 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), ...
随机推荐
- mysql sql技巧篇
1.left join 需要注意的事项 以左表为基准,匹配右表,如果右表匹配了两条,那么,就生成两条记录,而这两条记录的坐表信息都是一样的. 之前误以为,右表不会影响记录的条数.select 部分,不 ...
- Vaadin
Vaadin 这个是用Java 做的 一个人就可以完成 你去网上搜一下 教程 https://vaadin.com/home 官网 http://baike.baidu.com/link?url ...
- SQL Server游标【转】
什么是游标 结果集,结果集就是select查询之后返回的所有行数据的集合. 游标则是处理结果集的一种机制吧,它可以定位到结果集中的某一行,多数据进行读写,也可以移动游标定位到你所需要的行中进行操作 ...
- C#窗体:关于DataGridView的数据源绑定字符串两个值得注意的问题
无意间遇到的问题,然后就GOOGLE了下,搜到些资料,总结整理如下(注:是转载的) 1. LINQ的查询结果无法直接作为DataGridView的数据源 DataGridView的DataSource ...
- 蓝牙--主机接口控制器(HCI)
I提供对基带控制器和链路管理器的命令以及访问蓝牙硬件的统一接口,它是我们实现自己的蓝牙设备索要接触的第一个蓝牙协议,起着承上启下的作用. 1.概述 如下图所示,HCI通过对链路管理器.硬件状态注册器. ...
- 【Android测试】【随笔】获得App的包名和启动页Activity
◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/5157308.html 前言 经常看到一些刚刚接触Andro ...
- BI 商业智能理解结构图
本文章是在本人实习阶段对BI(商业智能 Business Intelligence)的理解:(如有不足之处请多指教,谢谢) BI 系统负责从多个数据源中搜集数据,并将这些数据进行必要的转换后存储到 ...
- 更改Magento的base url
Magento的Base URL是用于访问商店页面的URL,您也可以为单独一个store view设置一个Base Url.在改这项值之前请确保您的域名已经指向了网站所在服务器的IP,DNS解析完成后 ...
- Aptana Studio 3的汉化
Aptana Studio 3(下面简称Aptana 3)的汉化方法 1.找到这个网站 http://aptana.com/support 2.单击下面的链接 view documentation 在 ...
- 面向对象分析方法(I)
找出最关键的一些业务场景:一般通过动词来寻找,比如招聘系统中,一个应聘人投递一个职位就是一次应聘,应聘就是一个业务场景:一个学生参加某门课的考试,那么考试就是一个业务场景:一个学生去图书馆借书,那么借 ...