题目描述
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, return the ordering of courses you should take to finish all courses.
There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]
4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices.
算法描述
这道题是中等难度的题目,实质上就是拓扑排序的问题,就是构建一个用来记录每一个节点入度的数组in_degree和一个队列进行检查入度为0的节点zero_degree。
算法一开始先把每个节点的入度算出来,然后把入度为0的节点放进队列,然后进行一个循环,当队列不为空的时候,挑出队列的节点放到答案里面,并且将该节点去掉(把它的后续节点的入度减一),然后它后续节点入度为0的放进队列里面。
但是由于这道题给的是一个数组,所以要有一个内循环来找到该节点的后续节点,时间复杂度为O(M)(M指的是prerequisites的大小), 然后队列的时间复杂度为O(N),总的时间复杂度为O(NM)
如果想要继续优化的话,应当把这个 图的储存方式改变,变成一个邻接矩阵,那么在去除节点的时候时间复杂度会小很多。总的时间复杂度可以降到O(N+M)。为了方便没有进行转换。
代码如下:
vector<int> findOrder(int numCourses, vector<pair<int, int> >& prerequisites) {
vector<int> in_degree(numCourses);
for(int i = 0 ; i < prerequisites.size() ; i++)
in_degree[prerequisites[i].first]++;
vector<int> ans;
queue<int> zero_degree;
for(int i = 0 ; i < numCourses ; i++)
if(in_degree[i]==0){
zero_degree.push(i);
in_degree[i]= -1;
}
while(!zero_degree.empty()){
int i = zero_degree.front();
ans.push_back(i);
zero_degree.pop();
for(int j = 0 ; j < prerequisites.size();j++)
if(prerequisites[j].second==i){
if(--in_degree[prerequisites[j].first]==0)
zero_degree.push(prerequisites[j].first);
}
}
if(ans.size()==numCourses) return ans;
else{
//如果有不能够选到的节点,那么返回空集
vector<int> none;
return none;
}
}