题目:
题解:
- 拓扑排序,与207. 课程表代码一样的,只是将拓扑排序的顶点保留而已,注意边的数组给的是反向,这样的话,我们要将res反转就行了。
- 算法步骤:
- 1)遍历边的数组
prerequisites
建立图的邻接表
- 2)使用队列来存放入度为0的顶点,从而避免重复检测入度为0的顶点
- 3)删除入度为0的点,以及删除该点为起点的边,并统计删除入度为0的顶点个数
- 4)若有向图无环,则res.size()等于顶点数numCounses;否则有向图有环,则res.size()会小于顶点数numCounses
拓扑排序算法思路:
- 1)在有向图中选一个入度为0的顶点且输出之
- 2)从图中删除该顶点和所有以它为弧尾的弧
- 3)重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。=后者表示的是该有向图存在环。
代码如下:
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
map<int,set<int>> adjacent;//邻接表
vector<int> indegree(numCourses);//存放顶点入度的数组
//1、遍历图的边,建立邻接表和存放顶点入度的数组
for(auto& edge:prerequisites){
int a=edge[0],b=edge[1];
adjacent[a].insert(b);
++indegree[b];
}
//2、使用队列来存放入度为0的顶点,从而避免重复检测入度为0的顶点
queue<int> todo;
for(int i=0;i<numCourses;++i){
if(!indegree[i])todo.push(i);
}
//3、删除入度为0的点,以及删除该点为起点的边,并统计删除入度为0的顶点个数
vector<int> res;
while(!todo.empty()){
auto v=todo.front();//入度为0的顶点
todo.pop();
res.push_back(v);
auto & adjs=adjacent[v];//v的所有邻接点,即弧头为v所有弧的弧尾
//对v号顶点的每个邻接点的入度减1,若入度为0了,则加入队列中
for(auto adj:adjs){
--indegree[adj];
if(!indegree[adj])todo.push(adj);
}
}
//4、若有向图无环,则count等于顶点数numCounses;否则有向图有环,则count会小于顶点数numCounses
if(res.size()!=numCourses)return {};
//注意要将res反转因为图的边可以看成反向的,因此我们进行拓扑排序的结果需要反转
reverse(res.begin(),res.end());
return res;
}
};