Skip to content

Commit 91e3d47

Browse files
committed
207 Course Schedule
1 parent 366a00c commit 91e3d47

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
+ [204 Count Primes(素数,埃拉托斯特尼筛法)](algorithms/CountPrimes)
115115
+ [205 Isomorphic Strings](algorithms/IsomorphicStrings)
116116
+ [206 Reverse Linked List(链表转置,递归&迭代)](algorithms/ReverseLinkedList)
117+
+ [207 Course Schedule(拓扑排序、图是否存在环、BFS、DFS)](algorithms/CourseSchedule)
117118
+ [208 Implement Trie (Trie树、字典树、前缀树)](algorithms/ImplementTrie)
118119
+ [211 Add and Search Word - Data structure design(Trie树)](algorithms/AddandSearchWord)
119120

algorithms/CourseSchedule/README.md

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
## Course Schedule
2+
3+
There are a total of n courses you have to take, labeled from 0 to n - 1.
4+
5+
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
6+
7+
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
8+
9+
For example:
10+
11+
```
12+
2, [[1,0]]
13+
```
14+
15+
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
16+
17+
```
18+
2, [[1,0],[0,1]]
19+
```
20+
21+
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
22+
23+
Note:
24+
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
25+
26+
Hints:
27+
28+
* This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
29+
* Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
30+
* Topological sort could also be done via BFS.
31+
32+
## Solution
33+
34+
显然这是一道拓扑排序题。求拓扑排序的算法过程:
35+
36+
* 求出所有节点的入度`in-degree`
37+
* 搜索`in-degree`,找出入度为0的节点,若没有找到入读为0的节点,则一定存在环,返回false,否则,从节点中删除该节点,并与之相关联的所有有向边。
38+
* 重复以上,直到所有的节点访问完毕,返回true
39+
40+
首先求出所有的入度(注意题目的图是后面指向前面):
41+
42+
```cpp
43+
vector<int> degree(n, 0);
44+
for (auto p : request) {
45+
//g[p.second][p.first] = 1;
46+
degree[p.first]++;
47+
}
48+
```
49+
50+
寻找入度等于0的节点, 返回-1表示没有找到:
51+
52+
```cpp
53+
int findZero(const vector<int> &v) {
54+
int n = v.size();
55+
for (int i = 0; i < n; ++i) {
56+
if (v[i] == 0)
57+
return i;
58+
}
59+
return -1;
60+
}
61+
```
62+
63+
实现拓扑排序判断:
64+
65+
```cpp
66+
bool canTopsort(const vector<pair<int, int>> &request, vector<int> &degree) {
67+
int n = degree.size();
68+
vector<bool> visited(n, false);
69+
int sum = 0;
70+
while (sum < n) { // 还没有访问完
71+
int cur = findZero(degree);
72+
if (cur >= 0) { // 访问节点cur
73+
sum++;
74+
degree[cur] = -1; // 标记当前节点为已经访问状态
75+
for (auto p : request) {
76+
if (p.second == cur)
77+
degree[p.first]--; // 去掉已访问节点
78+
}
79+
} else
80+
return false;
81+
}
82+
return true;
83+
}
84+
```
85+
86+
以上方法实质就是BFS,也可以使用DFS,从一个节点出发,顺着边往下走,若回到已经访问的节点,说明存在环。
87+
88+
为了标示正在访问的节点、未访问节点和已经访问节点,我们分别使用-1, 0, 1表示。
89+
90+
```cpp
91+
bool dfs(const vector<pair<int, int>> &request, vector<int> &visited, int i) {
92+
if (visited[i] == -1) // 回到了出发点,说明存在环
93+
return false;
94+
if (visited[i] == 1) // 已经访问过该节点了
95+
return true;
96+
visited[i] = -1; // -1 表示正在访问
97+
for (auto p : request) {
98+
if (p.second == i) {
99+
if (!dfs(request, visited, p.first)) // 访问下一个节点
100+
return false;
101+
}
102+
}
103+
visited[i] = 1; // 标识为已经访问过
104+
return true;
105+
}
106+
107+
```
108+
## 扩展
109+
110+
[Course Schedule II](../CourseScheduleII): 输出拓扑排序结果

algorithms/CourseSchedule/bfs.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <cstdio>
2+
#include <cstdlib>
3+
#include <vector>
4+
#include <algorithm>
5+
#include <utility>
6+
#include <iostream>
7+
using namespace std;
8+
class Solution {
9+
public:
10+
bool canFinish(int n, vector<pair<int, int>> &request) {
11+
//vector<vector<int>> g(n, vector<int>(n, 0));
12+
vector<int> degree(n, 0);
13+
for (auto p : request) {
14+
//g[p.second][p.first] = 1;
15+
degree[p.first]++;
16+
}
17+
return topsort(request, degree);
18+
}
19+
private:
20+
/* BFS */
21+
bool topsort(const vector<pair<int, int>> &request, vector<int> &degree) {
22+
int n = degree.size();
23+
vector<bool> visited(n, false);
24+
int sum = 0;
25+
while (sum < n) { // 还没有访问完
26+
int cur = findZero(degree);
27+
if (cur >= 0) { // 访问节点cur
28+
sum++;
29+
degree[cur] = -1; // 标记当前节点为已经访问状态
30+
for (auto p : request) {
31+
if (p.second == cur)
32+
degree[p.first]--; // 去掉已访问节点
33+
}
34+
} else
35+
return false;
36+
}
37+
return true;
38+
}
39+
int findZero(const vector<int> &v) {
40+
int n = v.size();
41+
for (int i = 0; i < n; ++i) {
42+
if (v[i] == 0)
43+
return i;
44+
}
45+
return -1;
46+
}
47+
48+
};
49+
int main(int argc, char **argv)
50+
{
51+
Solution solution;
52+
vector<pair<int, int>> request = {make_pair(1, 0), make_pair(2, 1), make_pair(3, 1)};
53+
cout << solution.canFinish(4, request) << endl;
54+
return 0;
55+
}

algorithms/CourseSchedule/dfs.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <cstdio>
2+
#include <cstdlib>
3+
#include <vector>
4+
#include <algorithm>
5+
#include <utility>
6+
#include <iostream>
7+
using namespace std;
8+
class Solution {
9+
public:
10+
bool canFinish(int n, vector<pair<int, int>> &request) {
11+
vector<int> visited(n, 0);
12+
for (int i = 0; i < n; ++i)
13+
if (!dfs(request, visited, i))
14+
return false;
15+
return true;
16+
}
17+
private:
18+
bool dfs(const vector<pair<int, int>> &request, vector<int> &visited, int i) {
19+
if (visited[i] == -1)
20+
return false;
21+
if (visited[i] == 1)
22+
return true;
23+
visited[i] = -1; // -1 表示正在访问
24+
for (auto p : request) {
25+
if (p.second == i) {
26+
if (!dfs(request, visited, p.first))
27+
return false;
28+
}
29+
}
30+
visited[i] = 1;
31+
return true;
32+
}
33+
};
34+
int main(int argc, char **argv)
35+
{
36+
Solution solution;
37+
vector<pair<int, int>> request = {make_pair(1, 0), make_pair(2, 1), make_pair(0, 2)};
38+
cout << solution.canFinish(3, request) << endl;
39+
return 0;
40+
}

0 commit comments

Comments
 (0)