Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a13d3c6

Browse files
committed
started working on graph algorithms
1 parent 5069c8f commit a13d3c6

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
- [二分搜索](./basic_algorithm/binary_search.md)
3535
- [排序算法](./basic_algorithm/sort.md)
3636
- [动态规划](./basic_algorithm/dp.md)
37+
- [图相关算法](./basic_algorithm/graph/)
3738

3839
### 算法思维 🦁
3940

basic_algorithm/graph/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### 图相关算法
2+
3+
Ongoing...
4+
5+
[拓扑排序](./topological_sorting.md)
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# 拓扑排序
2+
3+
图的拓扑排序 (topological sorting) 一般用于给定一系列偏序关系,求一个全序关系的题目中。以元素为结点,以偏序关系为边构造有向图,然后应用拓扑排序算法即可得到全序关系。
4+
5+
### [course-schedule-ii](https://leetcode-cn.com/problems/course-schedule-ii/)
6+
7+
> 给定课程的先修关系,求一个可行的修课顺序
8+
9+
**图森面试真题**。非常经典的拓扑排序应用题目。下面给出 3 种实现方法,可以当做模板使用。
10+
11+
12+
13+
方法 1:DFS 的递归实现
14+
15+
```Python
16+
NOT_VISITED = 0
17+
DISCOVERING = 1
18+
VISITED = 2
19+
20+
class Solution:
21+
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
22+
23+
# construct graph
24+
graph_neighbor = collections.defaultdict(list)
25+
for course, pre in prerequisites:
26+
graph_neighbor[pre].append(course)
27+
28+
# recursive postorder DFS for topological sort
29+
tsort_rev = []
30+
status = [NOT_VISITED] * numCourses
31+
32+
def dfs(course):
33+
status[course] = DISCOVERING
34+
for n in graph_neighbor[course]:
35+
if status[n] == DISCOVERING or (status[n] == NOT_VISITED and not dfs(n)):
36+
return False
37+
tsort_rev.append(course)
38+
status[course] = VISITED
39+
return True
40+
41+
for course in range(numCourses):
42+
if status[course] == NOT_VISITED and not dfs(course):
43+
return []
44+
45+
return tsort_rev[::-1]
46+
```
47+
48+
方法 2:DFS 的迭代实现
49+
50+
```Python
51+
NOT_VISITED = 0
52+
DISCOVERING = 1
53+
VISITED = 2
54+
55+
class Solution:
56+
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
57+
58+
# construct graph
59+
graph_neighbor = collections.defaultdict(list)
60+
for course, pre in prerequisites:
61+
graph_neighbor[pre].append(course)
62+
63+
# iterative postorder DFS for topological sort
64+
tsort_rev = []
65+
status = [NOT_VISITED] * numCourses
66+
67+
dfs = []
68+
for course in range(numCourses):
69+
if status[course] == NOT_VISITED:
70+
dfs.append(course)
71+
status[course] = DISCOVERING
72+
73+
while dfs:
74+
if graph_neighbor[dfs[-1]]:
75+
n = graph_neighbor[dfs[-1]].pop()
76+
if status[n] == DISCOVERING:
77+
return []
78+
if status[n] == NOT_VISITED:
79+
dfs.append(n)
80+
status[n] = DISCOVERING
81+
else:
82+
tsort_rev.append(dfs.pop())
83+
status[tsort_rev[-1]] = VISITED
84+
85+
return tsort_rev[::-1]
86+
```
87+
88+
方法 3:[Kahn's algorithm](https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm)
89+
90+
```Python
91+
class Solution:
92+
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
93+
94+
# construct graph with indegree data
95+
graph_neighbor = collections.defaultdict(list)
96+
indegree = collections.defaultdict(int)
97+
98+
for course, pre in prerequisites:
99+
graph_neighbor[pre].append(course)
100+
indegree[course] += 1
101+
102+
# Kahn's algorithm
103+
src_cache = [] # can also use queue
104+
for i in range(numCourses):
105+
if indegree[i] == 0:
106+
src_cache.append(i)
107+
108+
tsort = []
109+
while src_cache:
110+
tsort.append(src_cache.pop())
111+
for n in graph_neighbor[tsort[-1]]:
112+
indegree[n] -= 1
113+
if indegree[n] == 0:
114+
src_cache.append(n)
115+
116+
return tsort if len(tsort) == numCourses else []
117+
```
118+
119+
### [alien-dictionary](https://leetcode-cn.com/problems/alien-dictionary/)
120+
121+
```Python
122+
class Solution:
123+
def alienOrder(self, words: List[str]) -> str:
124+
125+
N = len(words)
126+
127+
if N == 0:
128+
return ''
129+
130+
if N == 1:
131+
return words[0]
132+
133+
# construct graph
134+
indegree = {c: 0 for word in words for c in word}
135+
graph = collections.defaultdict(list)
136+
137+
for i in range(N - 1):
138+
first, second = words[i], words[i + 1]
139+
len_f, len_s = len(first), len(second)
140+
find_different = False
141+
for j in range(min(len_f, len_s)):
142+
f, s = first[j], second[j]
143+
if f != s:
144+
if s not in graph[f]:
145+
graph[f].append(s)
146+
indegree[s] += 1
147+
find_different = True
148+
break
149+
150+
if not find_different and len_f > len_s:
151+
return ''
152+
153+
tsort = []
154+
src_cache = [c for c in indegree if indegree[c] == 0]
155+
156+
while src_cache:
157+
tsort.append(src_cache.pop())
158+
for n in graph[tsort[-1]]:
159+
indegree[n] -= 1
160+
if indegree[n] == 0:
161+
src_cache.append(n)
162+
163+
return ''.join(tsort) if len(tsort) == len(indegree) else ''
164+
```
165+
166+
### [sequence-reconstruction](https://leetcode-cn.com/problems/sequence-reconstruction/)
167+
168+
Kahn's algorithm 可以判断拓扑排序是否唯一。
169+
170+
```Python
171+
class Solution:
172+
def sequenceReconstruction(self, org: List[int], seqs: List[List[int]]) -> bool:
173+
174+
N = len(org)
175+
inGraph = [False] * (N + 1)
176+
graph_set = collections.defaultdict(set)
177+
for seq in seqs:
178+
if seq:
179+
if seq[0] > N or seq[0] < 1:
180+
return False
181+
inGraph[seq[0]] = True
182+
for i in range(1, len(seq)):
183+
if seq[i] > N or seq[i] < 1:
184+
return False
185+
inGraph[seq[i]] = True
186+
graph_set[seq[i - 1]].add(seq[i])
187+
188+
indegree = collections.defaultdict(int)
189+
for node in graph_set:
190+
for n in graph_set[node]:
191+
indegree[n] += 1
192+
193+
num_valid, count0, src = 0, -1, 0
194+
for i in range(1, N + 1):
195+
if inGraph[i] and indegree[i] == 0:
196+
count0 += 1
197+
src = i
198+
199+
i = 0
200+
while count0 == i and src == org[i]:
201+
num_valid += 1
202+
for n in graph_set[src]:
203+
indegree[n] -= 1
204+
if indegree[n] == 0:
205+
count0 += 1
206+
src = n
207+
i += 1
208+
209+
return num_valid == N
210+
```
211+

0 commit comments

Comments
 (0)