-
Notifications
You must be signed in to change notification settings - Fork 90
/
Find the Weak Connected Component in the Directed Graph.py
107 lines (82 loc) · 2.63 KB
/
Find the Weak Connected Component in the Directed Graph.py
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
95
96
97
98
99
100
101
102
103
104
105
106
"""
Find the number Weak Connected Component in the directed graph. Each node in the graph contains a label and a list of
its neighbors. (a connected set of a directed graph is a subgraph in which any two vertices are connected by direct edge
path.)
Example
Given graph:
A----->B C
\ | |
\ | |
\ | |
\ v v
->D E <- F
Return {A,B,D}, {C,E,F}. Since there are two connected component which are {A,B,D} and {C,E,F}
Note
Sort the element in the set in increasing order
"""
class DirectedGraphNode:
def __init__(self, x):
self.label = x
self.neighbors = []
def __repr__(self):
return repr(self.x)
from collections import defaultdict
__author__ = 'Daniel'
class UnionFind(object):
"""
Weighted Union Find with path compression
"""
def __init__(self):
self.pi = {} # item -> pi
self.sz = {} # root -> size
def add(self, item):
if item not in self.pi:
self.pi[item] = item
self.sz[item] = 1
def union(self, a, b):
pi1 = self._pi(a)
pi2 = self._pi(b)
if pi1 != pi2:
if self.sz[pi1] > self.sz[pi2]:
pi1, pi2 = pi2, pi1
self.pi[pi1] = pi2
self.sz[pi2] += self.sz[pi1]
del self.sz[pi1]
def _pi(self, item):
pi = self.pi[item]
if item != pi:
self.pi[item] = self._pi(pi)
return self.pi[item]
def compress(self):
for item in self.pi.keys():
self.pi[item] = self._pi(item)
def count(self):
return len(self.sz) # only root nodes have size
class Solution:
def connectedSet2(self, nodes):
"""
Union-find
:param nodes: {DirectedGraphNode[]} nodes a array of directed graph node
:return: {int[][]} a connected set of a directed graph
"""
uf = UnionFind()
for node in nodes:
uf.add(node.label)
for nei in node.neighbors:
uf.add(nei.label)
uf.union(node.label, nei.label)
uf.compress()
ret = defaultdict(list)
for item, pi in uf.pi.items():
ret[pi].append(item)
for v in ret.values():
v.sort()
return ret.values()
if __name__ == "__main__":
items = {i: DirectedGraphNode(i) for i in "ABCDEF"}
items["A"].neighbors.append(items["B"])
items["A"].neighbors.append(items["D"])
items["B"].neighbors.append(items["D"])
items["C"].neighbors.append(items["E"])
items["F"].neighbors.append(items["E"])
assert Solution().connectedSet2(items.values()) == [['A', 'B', 'D'], ['C', 'E', 'F']]