-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplate.py
188 lines (152 loc) · 5.08 KB
/
template.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
from collections import defaultdict
def dfs(graph):
stack = [] # swap to queue for bfs
visited = set()
stack.append((0, 0))
# this dfs only adds neighbor of each element once
# but you can have an element multiple times in the stack
# because if A, B are in the stack and they both have a neighbor C, then C is added to the stack twice
while stack:
top = stack.pop()
if top is visited:
continue
visited.add(top)
for neighbor in graph[top]:
if neighbor not in visited:
stack.append(neighbor)
def dfs_recursive(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
for neighbor in graph[start]:
if neighbor not in visited:
dfs_recursive(graph, neighbor, visited)
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [0] * n
def find(self, x):
if self.parent[x] != x:
# path compression
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
# union by rank
px, py = self.find(x), self.find(y)
if px == py:
return False
if self.rank[px] < self.rank[py]:
self.parent[px] = py
elif self.rank[px] > self.rank[py]:
self.parent[py] = px
else:
self.parent[py] = px
self.rank[px] += 1
return True
# ---- TRIE -----
class TrieNode:
def __init__(self):
self.children = {}
self.endOfWord = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str) -> None:
cur = self.root
for c in word:
if c not in cur.children:
cur.children[c] = TrieNode()
cur = cur.children[c]
cur.endOfWord = True
def search(self, word: str) -> bool:
cur = self.root
for c in word:
if c not in cur.children:
return False
cur = cur.children[c]
return cur.endOfWord
def startsWith(self, prefix: str) -> bool:
cur = self.root
for c in prefix:
if c not in cur.children:
return False
cur = cur.children[c]
return True
def count_scc_clean_code_dirty_implementation(graph):
"""
Kosaraju's algorithm
step 1: dfs on the graph, to mark visited nodes and add them to the stack
step 2: transpose the graph
step 3: dfs on the transposed graph for every unvisited node until the stack is empty
step 4: count the number of times dfs is called
"""
def dfs(node, graph, o_stack, o_visited):
o_visited.add(node)
for neighbor in graph[node]:
if neighbor not in o_visited:
dfs(neighbor, graph, o_stack, o_visited)
o_stack.append(node)
def transpose(graph):
transposed = defaultdict(list)
for node in graph:
for neighbor in graph[node]:
transposed[neighbor].append(node)
return transposed
if not graph:
return 1
stack = []
visited = set()
for vertex in list(graph):
if vertex not in visited:
dfs(vertex, graph, stack, visited)
transpose_graph = transpose(graph)
visited.clear()
scc = 0
while len(visited) < len(graph): # or while stack (both works)
node = stack.pop()
if node not in visited:
dfs(node, transpose_graph, [], visited) # we don't need the stack here
scc += 1
return scc
def count_scc(graph):
"""
Kosaraju's algorithm
step 1: dfs on the graph, to mark visited nodes and add them to the stack
step 2: transpose the graph
step 3: dfs on the transposed graph for every unvisited node until the stack is empty
step 4: count the number of times dfs is called
"""
def dfs(node, graph, o_stack, o_visited):
o_visited.add(node)
for neighbor in graph[node]:
if neighbor not in o_visited:
dfs(neighbor, graph, o_stack, o_visited)
o_stack.append(node)
def dfs_scc(node, in_graph, o_visited):
o_visited.add(node)
for neighbor in in_graph[node]:
if neighbor not in o_visited:
dfs_scc(neighbor, in_graph, o_visited)
def transpose(graph):
transposed = defaultdict(list)
for node in graph:
for neighbor in graph[node]:
transposed[neighbor].append(node)
return transposed
if not graph:
return 1
stack = []
visited = set()
for vertex in list(graph):
if vertex not in visited:
dfs(vertex, graph, stack, visited)
transpose_graph = transpose(graph)
visited.clear()
scc = 0
while len(visited) < len(graph): # or while stack (both works)
node = stack.pop()
if node not in visited:
# could just use dfs with [] stack
dfs_scc(node, transpose_graph, visited) # we don't need the stack here
scc += 1
return scc