题目描述
There are a total of n courses you have to take, labeled from 0
to n-1
.
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]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
Example1:
Input: 2, [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
Example2:
Input: 2, [[1,0],[0,1]]
Output: false
Explanation: 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.
Note:
- The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
- You may assume that there are no duplicate edges in the input prerequisites.
解题思路
该问题中,我们可以根据课程学习的先后顺序构建一张有向图,其中,若课程a必须在修完课程b后才可以学习,那么该有向图中有一条边,由b指向a。在构建完有向图之后,该问题便变成了有向图中是否存在一个环,若存在环,便无法学习完所有课程,反之亦然。我们可以使用拓扑排序算法简单、高效的判断一个有向图中是否存在一个环,时间复杂度为 ,其中 表示顶点个数, 表示边的个数。
拓扑排序步骤
- 遍历图中所有的边,记录下每个定点的入度。
- 遍历所有定点的入度,将入度为0的顶点压入一个队列。
- 当队列不为空时,抛出队列中第一个元素,否则跳到步骤5.
- 将所有从抛出点可到达的顶点的入度减一,若某个点的入度为0,则加入队列尾部。循环辉步骤3。
- 检查所有定点的入度,若存在一个顶点入度不为0,则该有向图存在环,否则不存在。
代码:
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
//新建队列
queue<int> q;
//初始化有向图
bool map[numCourses][numCourses] = {};
//记录顶点入度的数组
int in[numCourses] = {};
//根据输入构建有向图
for (auto iter : prerequisites) {
map[iter.second][iter.first] = true;
in[iter.first]++;
}
//入度为0的点入队
for (int i = 0; i < numCourses; i++) {
if (in[i] == 0) {
q.push(i);
}
}
//循环求解
while(!q.empty()) {
int course = q.front();
q.pop();
for (int i = 0; i < numCourses; i++) {
if (map[course][i]) {
if (--in[i] == 0) {
q.push(i);
}
}
}
}
//检查是否还存在入度不为0的点
for (int i = 0; i < numCourses; i++) {
if (in[i] != 0) return false;
}
return true;
}
};
运行结果: