-
Notifications
You must be signed in to change notification settings - Fork 0
/
207. Course Schedule(DFS).js
147 lines (127 loc) · 4.04 KB
/
207. Course Schedule(DFS).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
140
141
142
143
144
145
146
147
/**
* Note:
* 1. Adjacency List: HashMap(parent node(number), children nodes(array)), key, value can reverse
* 2. Visited Array: index: node, value: 1-> has loop, -1-> not has loop
* 3. DFS:
* a. input(Adjacency HashMap, Visited Array, iteration index i) NOT NECESSARY
pass data structure because DFS out of canFind block scope
* b. if visited[i] === -1, return false, if visited[i] === 1, return true
* c. set visited[i] === 1, check if any all children visited[node] === 1, set visited[i] === 1
* d. return false
* 4. if DFS is true, return false, else return true
* 5. Remember to return true outside of the numCourses loop
*/
'use strict';
/**
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {boolean}
*/
var canFinish = function(numCourses, prerequisites) {
if (numCourses === 0) {
return true;
}
if (prerequisites.length === 0 || prerequisites[0].length === 0) {
return true;
}
if (prerequisites === null) {
throw new Error('illegal argument exception!');
}
let length = prerequisites.length;
let graph = new Map();
let visited = new Array(numCourses).fill(0);
//Build graph
for (let edges of prerequisites) {
if (graph.has(edges[1])) {
graph.get(edges[1]).push(edges[0]);
continue
}
let children = new Array();
children.push(edges[0]);
graph.set(edges[1], children);
}
for (let i = 0; i < numCourses; i++) {
if (dfs(i)) {
return false;
}
}
return true;
/*
* @param {number} iteration index
* @return {boolean} has loop or not
*/
function dfs(node) {
if (visited[node] === -1) return false;
if (visited[node] === 1) return true;
visited[node] = 1;
if (graph.has(node)) {
for (let child of graph.get(node)) { // iterate children
if (dfs(child)) {
return true;
}
}
}
visited[node] = -1;
return false;
}
};
let test1 = [[0, 1], [1, 2], [2, 3]];
console.log(canFinish(4, test1));
let test2 = [[0, 1], [1, 0]];
console.log(canFinish(2, test2));
/**
* Leetcode Fundamental: 11/14 Update
* 0. Directed Graph
* 1. Adjacency List: HashMap(parent node(number), children nodes(array))
* 2. Node States Array: index: node, value: 0-> unvisited(default), 1-> has cycle, -1-> not has cycle
* 3. Construct AdjList from prerequisites
* 4. Declare hasCycle helper func(node, adjList, state)
* 5. Iterate all nodes, if any of it has cycle, return false, else return true
*
* T: O(n), S: AdjList: O(Edge), State: O(n), O(Edge + n)
* 72 ms
*/
/**
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {boolean}
*/
var canFinish = function(numCourses, prerequisites) {
// Handle edge cases
if (numCourses === undefined || prerequisites === undefined) return false;
if (numCourses === 0) return true;
// No dependency
if (prerequisites.length === 0 || prerequisites[0].length === 0) return true;
// Construct AdjList(build graph)
let adjList = {};
for (let edge of prerequisites) {
let parent = edge[1];
let child = edge[0];
if (parent in adjList) adjList[parent].push(child);
else adjList[parent] = [child];
}
// Initiate node states
let state = new Array(numCourses).fill(0);
// Iterate each node and check cycle
for (let i = 0; i < numCourses; i += 1) {
if (hasCycle(i, adjList, state)) return false;
}
return true;
};
const hasCycle = (node, adjList, state) => {
// Check node cycle state
if (state[node] === -1) return false;
if (state[node] === 1) return true;
// Update node cycle state
// Label to has cycle first(state[node] = 1), if recursively find any children have cycle -> return true
// else: reset state to has no cycle(state[node] = -1)
// return false;
state[node] = 1;
if (node in adjList) {
for (let child of adjList[node]) {
if (hasCycle(child, adjList, state)) return true;
}
}
state[node] = -1;
return false;
};