Skip to content

Commit ed94064

Browse files
committed
update lc 207, topological cheatsheet
1 parent aa8d52a commit ed94064

File tree

2 files changed

+236
-127
lines changed

2 files changed

+236
-127
lines changed

doc/cheatsheet/topology_sorting.md

Lines changed: 235 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,241 @@ print (r)
104104

105105
## 2) LC Example
106106

107-
### 2-1) Course Schedule
107+
### 2-2) Course Schedule II
108+
109+
```java
110+
// java
111+
// LC 210
112+
public class CourseSchedule2 {
113+
114+
// V0
115+
// IDEA : TOPOLOGICAL SORT (fixed by gpt)
116+
// ref : https://github.com/yennanliu/CS_basics/blob/master/leetcode_java/src/main/java/AlgorithmJava/TopologicalSortV2.java
117+
public int[] findOrder(int numCourses, int[][] prerequisites) {
118+
if (numCourses == 1) {
119+
return new int[]{0};
120+
}
121+
122+
// topologic ordering
123+
List<Integer> ordering = topologicalSort(numCourses, prerequisites);
124+
//System.out.println(">>> ordering = " + ordering);
125+
if (ordering == null){
126+
return new int[]{};
127+
}
128+
int[] res = new int[numCourses];
129+
for (int x = 0; x < ordering.size(); x++) {
130+
int val = ordering.get(x);
131+
//System.out.println(val);
132+
res[x] = val;
133+
}
134+
135+
return res;
136+
}
137+
138+
public List<Integer> topologicalSort(int numNodes, int[][] edges) {
139+
// Step 1: Build the graph and calculate in-degrees
140+
Map<Integer, List<Integer>> graph = new HashMap<>();
141+
int[] inDegree = new int[numNodes];
142+
143+
for (int i = 0; i < numNodes; i++) {
144+
graph.put(i, new ArrayList<>());
145+
}
146+
147+
for (int[] edge : edges) {
148+
int from = edge[0];
149+
int to = edge[1];
150+
graph.get(from).add(to);
151+
inDegree[to]++;
152+
}
153+
154+
// Step 2: Initialize a queue with nodes that have in-degree 0
155+
Queue<Integer> queue = new LinkedList<>();
156+
for (int i = 0; i < numNodes; i++) {
157+
/**
158+
* NOTE !!!
159+
*
160+
* we add ALL nodes with degree = 0 to queue at init step
161+
*/
162+
if (inDegree[i] == 0) {
163+
queue.offer(i);
164+
}
165+
}
166+
167+
List<Integer> topologicalOrder = new ArrayList<>();
168+
169+
// Step 3: Process the nodes in topological order
170+
while (!queue.isEmpty()) {
171+
/**
172+
* NOTE !!!
173+
*
174+
* ONLY "degree = 0" nodes CAN be added to queue
175+
*
176+
* -> so we can add whatever node from queue to final result (topologicalOrder)
177+
*/
178+
int current = queue.poll();
179+
topologicalOrder.add(current);
180+
181+
for (int neighbor : graph.get(current)) {
182+
inDegree[neighbor] -= 1;
183+
/**
184+
* NOTE !!!
185+
*
186+
* if a node "degree = 0" means this node can be ACCESSED now,
187+
*
188+
* -> so we need to add it to the queue (for adding to topologicalOrder in the following while loop iteration)
189+
*/
190+
if (inDegree[neighbor] == 0) {
191+
queue.offer(neighbor);
192+
}
193+
}
194+
}
195+
196+
// If topologicalOrder does not contain all nodes, there was a cycle in the graph
197+
if (topologicalOrder.size() != numNodes) {
198+
//throw new IllegalArgumentException("The graph has a cycle, so topological sort is not possible.");
199+
return null;
200+
}
201+
202+
/** NOTE !!! reverse ordering */
203+
Collections.reverse(topologicalOrder);
204+
return topologicalOrder;
205+
}
206+
207+
```
208+
209+
```python
210+
# LC 210 Course Schedule II
211+
# V0
212+
# IDEA : DFS + topological sort
213+
# SAME dfs logic as LC 207 (Course Schedule)
214+
from collections import defaultdict
215+
class Solution(object):
216+
def findOrder(self, numCourses, prerequisites):
217+
# edge case
218+
if not prerequisites:
219+
return [x for x in range(numCourses)]
220+
221+
# help func : dfs
222+
# 3 cases : 0 : unknown, 1 :visiting, 2 : visited
223+
def dfs(idx, visited, g, res):
224+
if visited[idx] == 1:
225+
return False
226+
# NOTE !!! if visited[idx] == 2, means already visited, return True directly (and check next idx in range(numCourses))
227+
if visited[idx] == 2:
228+
return True
229+
visited[idx] = 1
230+
"""
231+
NOTE this !!!
232+
233+
1) for j in g[idx] (but not for i in range(numCourses))
234+
2) go through idx in g[idx]
235+
"""
236+
for j in g[idx]:
237+
if not dfs(j, visited, g, res):
238+
return False
239+
"""
240+
don't forget to make idx as visited (visited[idx] = 2)
241+
"""
242+
visited[idx] = 2
243+
"""
244+
NOTE : the main difference between LC 207, 210
245+
246+
-> we append idx to res (our ans)
247+
"""
248+
res.append(idx)
249+
return True
250+
# init
251+
visited = [0] * numCourses
252+
# build grath
253+
g = defaultdict(list)
254+
for p in prerequisites:
255+
g[p[0]].append(p[1])
256+
res = []
257+
"""
258+
NOTE : go through idx in numCourses (for idx in range(numCourses))
259+
"""
260+
for idx in range(numCourses):
261+
if not dfs(idx, visited, g, res):
262+
return []
263+
return res
264+
265+
# V0'
266+
# IDEA : DFS + topological sort
267+
# SAME dfs logic as LC 207 (Course Schedule)
268+
import collections
269+
class Solution:
270+
def findOrder(self, numCourses, prerequisites):
271+
# build graph
272+
_graph = collections.defaultdict(list)
273+
for i in range(len(prerequisites)):
274+
_graph[prerequisites[i][0]].append(prerequisites[i][1])
275+
276+
visited = [0] * numCourses
277+
res = []
278+
for i in range(numCourses):
279+
if not self.dfs(_graph, visited, i, res):
280+
return []
281+
print ("res = " + str(res))
282+
return res
283+
284+
# 0 : unknown, 1 :visiting, 2 : visited
285+
def dfs(self, _graph, visited, i, res):
286+
if visited[i] == 1:
287+
return False
288+
if visited[i] == 2:
289+
return True
290+
visited[i] = 1
291+
for item in _graph[i]:
292+
if not self.dfs(_graph, visited, item, res):
293+
return False
294+
visited[i] = 2
295+
res.append(i)
296+
return True
297+
298+
# V0'
299+
# IDEA : DFS + topological sort
300+
# SAME dfs logic as LC 207 (Course Schedule)
301+
class Solution(object):
302+
def findOrder(self, numCourses, prerequisites):
303+
"""
304+
:type numCourses: int
305+
:type prerequisites: List[List[int]]
306+
:rtype: List[int]
307+
"""
308+
graph = collections.defaultdict(list)
309+
for u, v in prerequisites:
310+
graph[u].append(v)
311+
# 0 = Unknown, 1 = visiting, 2 = visited
312+
visited = [0] * numCourses
313+
path = []
314+
for i in range(numCourses):
315+
### NOTE : if not a valid "prerequisites", then will return NULL list
316+
if not self.dfs(graph, visited, i, path):
317+
return []
318+
return path
319+
320+
def dfs(self, graph, visited, i, path):
321+
# 0 = Unknown, 1 = visiting, 2 = visited
322+
if visited[i] == 1: return False
323+
if visited[i] == 2: return True
324+
visited[i] = 1
325+
for j in graph[i]:
326+
if not self.dfs(graph, visited, j, path):
327+
### NOTE : the quit condition
328+
return False
329+
visited[i] = 2
330+
path.append(i)
331+
return True
332+
```
333+
334+
### 2-2) Course Schedule
335+
336+
```java
337+
// java
338+
// LC 207
339+
// same as LC 210
340+
```
341+
108342
```python
109343
# LC 207 Course Schedule
110344
# NOTE : there are also bracktrack, dfs approachs for this problem
@@ -327,132 +561,6 @@ class Solution:
327561
return len(stack) == numCourses
328562
```
329563

330-
### 2-2) Course Schedule II
331-
```python
332-
# LC 210 Course Schedule II
333-
# V0
334-
# IDEA : DFS + topological sort
335-
# SAME dfs logic as LC 207 (Course Schedule)
336-
from collections import defaultdict
337-
class Solution(object):
338-
def findOrder(self, numCourses, prerequisites):
339-
# edge case
340-
if not prerequisites:
341-
return [x for x in range(numCourses)]
342-
343-
# help func : dfs
344-
# 3 cases : 0 : unknown, 1 :visiting, 2 : visited
345-
def dfs(idx, visited, g, res):
346-
if visited[idx] == 1:
347-
return False
348-
# NOTE !!! if visited[idx] == 2, means already visited, return True directly (and check next idx in range(numCourses))
349-
if visited[idx] == 2:
350-
return True
351-
visited[idx] = 1
352-
"""
353-
NOTE this !!!
354-
355-
1) for j in g[idx] (but not for i in range(numCourses))
356-
2) go through idx in g[idx]
357-
"""
358-
for j in g[idx]:
359-
if not dfs(j, visited, g, res):
360-
return False
361-
"""
362-
don't forget to make idx as visited (visited[idx] = 2)
363-
"""
364-
visited[idx] = 2
365-
"""
366-
NOTE : the main difference between LC 207, 210
367-
368-
-> we append idx to res (our ans)
369-
"""
370-
res.append(idx)
371-
return True
372-
# init
373-
visited = [0] * numCourses
374-
# build grath
375-
g = defaultdict(list)
376-
for p in prerequisites:
377-
g[p[0]].append(p[1])
378-
res = []
379-
"""
380-
NOTE : go through idx in numCourses (for idx in range(numCourses))
381-
"""
382-
for idx in range(numCourses):
383-
if not dfs(idx, visited, g, res):
384-
return []
385-
return res
386-
387-
# V0'
388-
# IDEA : DFS + topological sort
389-
# SAME dfs logic as LC 207 (Course Schedule)
390-
import collections
391-
class Solution:
392-
def findOrder(self, numCourses, prerequisites):
393-
# build graph
394-
_graph = collections.defaultdict(list)
395-
for i in range(len(prerequisites)):
396-
_graph[prerequisites[i][0]].append(prerequisites[i][1])
397-
398-
visited = [0] * numCourses
399-
res = []
400-
for i in range(numCourses):
401-
if not self.dfs(_graph, visited, i, res):
402-
return []
403-
print ("res = " + str(res))
404-
return res
405-
406-
# 0 : unknown, 1 :visiting, 2 : visited
407-
def dfs(self, _graph, visited, i, res):
408-
if visited[i] == 1:
409-
return False
410-
if visited[i] == 2:
411-
return True
412-
visited[i] = 1
413-
for item in _graph[i]:
414-
if not self.dfs(_graph, visited, item, res):
415-
return False
416-
visited[i] = 2
417-
res.append(i)
418-
return True
419-
420-
# V0'
421-
# IDEA : DFS + topological sort
422-
# SAME dfs logic as LC 207 (Course Schedule)
423-
class Solution(object):
424-
def findOrder(self, numCourses, prerequisites):
425-
"""
426-
:type numCourses: int
427-
:type prerequisites: List[List[int]]
428-
:rtype: List[int]
429-
"""
430-
graph = collections.defaultdict(list)
431-
for u, v in prerequisites:
432-
graph[u].append(v)
433-
# 0 = Unknown, 1 = visiting, 2 = visited
434-
visited = [0] * numCourses
435-
path = []
436-
for i in range(numCourses):
437-
### NOTE : if not a valid "prerequisites", then will return NULL list
438-
if not self.dfs(graph, visited, i, path):
439-
return []
440-
return path
441-
442-
def dfs(self, graph, visited, i, path):
443-
# 0 = Unknown, 1 = visiting, 2 = visited
444-
if visited[i] == 1: return False
445-
if visited[i] == 2: return True
446-
visited[i] = 1
447-
for j in graph[i]:
448-
if not self.dfs(graph, visited, j, path):
449-
### NOTE : the quit condition
450-
return False
451-
visited[i] = 2
452-
path.append(i)
453-
return True
454-
```
455-
456564
### 2-3) alien-dictionary
457565
```python
458566
# 269 alien-dictionary

leetcode_java/src/main/java/LeetCodeJava/BFS/CourseSchedule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
public class CourseSchedule {
88

9+
// V0
910
// IDEA : TOPOLOGICAL SORT
1011
// LC 210
1112
public boolean canFinish(int numCourses, int[][] prerequisites) {

0 commit comments

Comments
 (0)