Skip to content

Commit fbb7785

Browse files
Chris WuChris Wu
Chris Wu
authored and
Chris Wu
committed
graph valid tree
1 parent fa8ab46 commit fbb7785

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

graph-valid-tree.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"""
2+
First of all a tree of N nodes must have exactly N-1 edges.
3+
2 nodes need 1 edge to connect. 3 nodes need 2 edges to connect...
4+
Just draw one or two, you will know it.
5+
6+
Valid tree don't have cycles, there are two ways to detect it.
7+
DFS. and union find. Union find is more suitable in this sutuation.
8+
9+
1. Union find.
10+
We use an array 'markset' to store the root node of each node. [0]
11+
So if markset[1]==3, it means node1's root is node3.
12+
markset[6]==4, node6's root is node4.
13+
14+
we use find() to find the node's root. [1]
15+
For example if node1's root is node3.
16+
In the recursion, we find out that node3's root is node5.
17+
we return and set node5 as node1's real root.
18+
If a node don't have root then the root is itselves.
19+
20+
Imagine an edge. 1<->6 [2]
21+
union()'s mission is to find out if node1 and node6 share the same root before we know 1<->6 exist.
22+
If node1 and node6 share the same root before we know the edge 1<->6,
23+
There must be a cycle between node1, node6 and their root.
24+
25+
A special situation is that
26+
1<->2, 3<->4, 3<->5 (We have two trees that are not connected)
27+
1 and 3 will share -1 as 'root', this means that they are not connected.
28+
But a valid tree should be connected and only have one and only root.
29+
30+
The time complexity is O(NLogN), becuase we run a loop for every edges.
31+
And the number of edges is equal to N-1
32+
for every edge we use find() to find the root of two nodes
33+
The recursion takes the height of the tree, which is LogN
34+
N is the number of nodes.
35+
36+
Space complexity is O(N).
37+
38+
2. DFS
39+
We use dfs to find if there are cycles in the tree.
40+
If we visit the node that we visited which means there is a cycle.
41+
Since this is an undirected map, we have to add both ways to the adjacent list.
42+
And everytime we use an edge, we need to remove the counter part of it to avoid repeat.
43+
finally, we have to check if we visit all the nodes. because there may be unconnected nodes.
44+
45+
The time complexity is O(N+E). Because this is DFS search in adjacent list.
46+
Space complexity is O(N).
47+
"""
48+
class Solution(object):
49+
def validTree(self, n, edges):
50+
def union(n1, n2): #[2]
51+
n1_root = find(n1)
52+
n2_root = find(n2)
53+
if n1_root==n2_root: return True
54+
markset[n2_root] = n1_root
55+
return False
56+
57+
def find(node): #[1]
58+
if markset[node]==-1: return node
59+
return find(markset[node])
60+
61+
if len(edges)!=n-1: return False
62+
markset = [-1 for _ in xrange(n)] #[0]
63+
64+
for edge in edges:
65+
if union(edge[0], edge[1]): return False
66+
67+
return True
68+
69+
70+
def validTree(self, n, edges):
71+
if n!=len(edges)+1: return False
72+
73+
graph = collections.defaultdict(list)
74+
stack = []
75+
visited = set()
76+
77+
for edge in edges:
78+
graph[edge[0]].append(edge[1])
79+
graph[edge[1]].append(edge[0])
80+
81+
if len(edges)>0:
82+
stack.append(edges[0][0])
83+
84+
while stack:
85+
node = stack.pop()
86+
if node in visited: return False
87+
visited.add(node)
88+
for nb in graph[node]:
89+
stack.append(nb)
90+
graph[nb].remove(node)
91+
92+
if len(visited)!=n: return False
93+
94+
return True

0 commit comments

Comments
 (0)