-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy path207. Course Schedule.cpp
120 lines (106 loc) · 4.32 KB
/
207. Course Schedule.cpp
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
//https://www.geeksforgeeks.org/detect-cycle-in-a-graph/
//Runtime: 24 ms, faster than 64.54% of C++ online submissions for Course Schedule.
//Memory Usage: 12.7 MB, less than 100.00% of C++ online submissions for Course Schedule.
class Solution {
public:
bool isCyclicUtil(int cur, unordered_map<int, vector<int>>& edges, vector<bool>& visited, vector<bool>& recStack){
visited[cur] = true;
recStack[cur] = true;
/*
3
[[0,1],[0,2],[1,2]]
(according to the problem description, the edge is represented as [dst, src])
In the example:
there are two paths :
2->0
2->1->0
If we go through the first path first, 0 will be marked as visited,
later when we go through the second path, we will see 0 as visited,
if we only use "visited" to detect cycle, it will fail in this case,
so we need "recStack" to check if 0 is on our path
*/
for(int nei : edges[cur]){
// cout << cur << " -- " << nei << endl;
/*
the first part can be written as:
if(!visited[nei] && isCyclicUtil(nei, edges, visited, recStack))
because in the second part, if recStack[nei] is true,
then visited[nei] must be true, so it will skip first part anyway
*/
if(!visited[nei]){
//find whether its neighbor is cyclic
if(isCyclicUtil(nei, edges, visited, recStack)){
return true;
}
}else if(recStack[nei]){
//that means nei is both cur's ancestor and its descendent
// cout << cur << " -- " << nei << ", nei in recStack" << endl;
return true;
}
}
//recStack is restored(because we finish this layer of recursion)
recStack[cur] = false;
//Note that visited[cur] is not restored
return false;
};
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<bool> visited(numCourses, false);
vector<bool> recStack(numCourses, false);
bool hasCycle = false;
unordered_map<int, vector<int>> edges;
for(vector<int>& pre : prerequisites){
/*
this is correct according to the problem definition
pre[1] should be taken before pre[0],
so the edge is from pre[1] to pre[0]
*/
edges[pre[1]].push_back(pre[0]);
//however this also gives correct answer
// edges[pre[0]].push_back(pre[1]);
}
for(int i = 0; i < numCourses; i++){
if(!visited[i]){
if(isCyclicUtil(i, edges, visited, recStack)){
//we have cycle
hasCycle = true;
break;
}
}
}
return !hasCycle;
}
};
//topological sort, bfs
//https://leetcode.com/problems/course-schedule/discuss/58516/Easy-BFS-Topological-sort-Java
//Runtime: 24 ms, faster than 64.54% of C++ online submissions for Course Schedule.
//Memory Usage: 10.8 MB, less than 100.00% of C++ online submissions for Course Schedule.
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> incomingEdgeCount(numCourses, 0);
vector<vector<int>> edges(numCourses);
for(vector<int>& pre : prerequisites){
//pre[1] points to pre[0](pre[1] should be taken before pre[0])
incomingEdgeCount[pre[0]]++;
edges[pre[1]].push_back(pre[0]);
}
queue<int> noIncomingEdges;
for(int i = 0; i < numCourses; i++){
if(incomingEdgeCount[i] == 0){
noIncomingEdges.push(i);
}
}
int remainingEdgeCount = prerequisites.size();
while(!noIncomingEdges.empty()){
int cur = noIncomingEdges.front(); noIncomingEdges.pop();
for(int nei : edges[cur]){
remainingEdgeCount--;
if(--incomingEdgeCount[nei] == 0){
noIncomingEdges.push(nei);
}
}
}
//if there are redundant edges, there is a cycle
return remainingEdgeCount == 0;
}
};