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