点击:题目链接:你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
思路
该题用的是有向图的拓扑排序。
主要的算法逻辑顺序:
- 找到所有没有入度的节点
- 移除这些节点的所有出度,同时与之有关联的出度的节点,他们的入度减一。同时记录移除的节点个数
- 重复2,直到无满足条件的节点
- 对比记录的移除的个数,是否与原有向图节点个数相等,若不等,则有环
代码
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
| class Solution { public: bool canFinish(int numCourses, vector<vector<int>>& prerequisites) { vector<vector<int>> edge; edge.resize(numCourses); vector<int> inedge = vector<int>(numCourses);
for(auto info:prerequisites){ edge[info[1]].push_back(info[0]); ++inedge[info[0]]; }
queue<int> q;
for(int i=0; i< edge.size(); i++){ if(inedge[i] == 0){ q.push(i); } }
int visited = 0; while(!q.empty()){ ++visited;
int u = q.front(); q.pop(); for(int v:edge[u]){ --inedge[v]; if(inedge[v] == 0){ q.push(v); } } }
return visited==numCourses; } };
|
复杂度
时间O(m+n),空间O(m+n)