forked from neetcode-gh/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
0210-course-schedule-ii.js
139 lines (108 loc) · 4.03 KB
/
0210-course-schedule-ii.js
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
/**
* https://leetcode.com/problems/course-schedule-ii/
* Time O(V + E) | Space O(V + E)
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {number[]}
*/
var findOrder = function(numCourses, prerequisites) {
const { graph, color, isDirectedAcyclicGraph, topologicalOrder } = buildGraph(numCourses, prerequisites);
search(numCourses, graph, color, topologicalOrder, isDirectedAcyclicGraph)
return isDirectedAcyclicGraph[0]
? topologicalOrder.reverse()
: []
}
var initGraph = (numCourses) => ({
graph: new Array(numCourses).fill().map(() => []),
color: new Array(numCourses).fill(1), // White
isDirectedAcyclicGraph: [ true ],
topologicalOrder: []
})
var buildGraph = (numCourses, prerequisites) => {
const { graph, color, isDirectedAcyclicGraph, topologicalOrder } = initGraph(numCourses);
for (const [ src, dst ] of prerequisites) {
const neighbors = (graph[dst] || []);
neighbors.push(src);
graph[dst] = neighbors;
}
return { graph, color, isDirectedAcyclicGraph, topologicalOrder }
}
var search = (numCourses, graph, color, topologicalOrder, isDirectedAcyclicGraph) => {
for (let i = 0; i < numCourses; i++) {
const isNew = color[i] === 1 // White
if (isNew) dfs(i, graph, color, topologicalOrder, isDirectedAcyclicGraph);
}
}
var dfs = (node, graph, color, topologicalOrder, isDirectedAcyclicGraph) => {
const hasCycle = !isDirectedAcyclicGraph[0]
if (hasCycle) return;
colorBackTrack(node, graph, color, topologicalOrder, isDirectedAcyclicGraph)
topologicalOrder.push(node);
}
const colorBackTrack = (node, graph, color, topologicalOrder, isDirectedAcyclicGraph) => {
color[node] = 2; // Grey
checkNeighbors(node, graph, color, topologicalOrder, isDirectedAcyclicGraph)
color[node] = 3; // Black
}
var checkNeighbors = (node, graph, color, topologicalOrder, isDirectedAcyclicGraph) => {
for (const neighbor of graph[node]) {
const isNew = color[neighbor] === 1 // White
if (isNew) dfs(neighbor, graph, color, topologicalOrder, isDirectedAcyclicGraph);
const isCycle = color[neighbor] === 2 // Grey
if (isCycle) isDirectedAcyclicGraph[0] = false;
}
}
/**
* https://leetcode.com/problems/course-schedule-ii/
* Time O(V + E) | Space O(V + E)
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {number[]}
*/
var findOrder = function(numCourses, prerequisites) {
const { graph, indegree } = buildGraph(numCourses, prerequisites);
const reversedTopologicalOrder = topologicalSort(graph, indegree);
const isDirectedAcyclicGraph = reversedTopologicalOrder.length === numCourses;
return isDirectedAcyclicGraph
? reversedTopologicalOrder
: [];
};
var initGraph = (numCourses) => ({
graph: new Array(numCourses).fill().map(() => []),
indegree: new Array(numCourses).fill(0)
})
var buildGraph = (numCourses, prerequisites) => {
const { graph, indegree } = initGraph(numCourses);
for (const [ src, dst ] of prerequisites){
graph[src].push(dst);
indegree[dst]++;
}
return { graph, indegree };
}
var topologicalSort = (graph, indegree) => {
const queue = searchGraph(graph, indegree);
return bfs(graph, indegree, queue);
}
var isSource = (count) => count === 0;
var searchGraph = (graph, indegree, queue = new Queue([])) => {
for (const node in graph) {
if (isSource(indegree[node])) queue.enqueue(node);
}
return queue;
}
var bfs = (graph, indegree, queue, reversedOrder = []) => {
while (!queue.isEmpty()) {
for (let i = (queue.size() - 1); 0 <= i; i--) {
checkNeighbors(graph, indegree, queue, reversedOrder);
}
}
return reversedOrder.reverse();
}
var checkNeighbors = (graph, indegree, queue, reversedOrder) => {
const node = queue.dequeue();
reversedOrder.push(node);
for (const neighbor of graph[node]) {
indegree[neighbor]--;
if (isSource(indegree[neighbor])) queue.enqueue(neighbor);
}
}