图的拓扑排序问题
第一次做图的拓扑排序问题,这里以代码注释的方式记录一下广度优先搜索的方式分析该问题的过程。
题目描述
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解答思路
1、首先需要一个数组存放以某一顶点为起点的所有的边,大小为numCourses
2、需要一个记录顶点入度的数组,大小为numCourses
3、上述两个数组可以在遍历整个prerequisites数组的时候初始化
4、需要一个数组存放结果
5、需要一个队列来辅助整个遍历过程,这个跟树的层序遍历以及无向图的广度优先搜索类似,队列中始终只存放入度为0的顶点
6、循环中每次取出队列的首部,放入result数组中,将所有起点为该首部的所有边的的终点的入度-1,如果入度变为0,则放入队列中。
7、循环结束后,判断result的大小是否为numCourses,以此来判断能否学习完课程(该有向图中是否存在环),否则输出空数组。
class Solution {
private:
vector<vector<int>> edge;//存放边起点--->终点
vector<int> indeg;//存放终点的入度
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> result;//存放遍历结果
edge.resize(numCourses);//边的数量初始化为课程数量的大小
indeg.resize(numCourses);//顶点的数量初始化为课程数量的大小
for(auto info : prerequisites){
edge[info[1]].push_back(info[0]);//起点到终点,info[0]是终点
indeg[info[0]] ++;//终点的入度
}
queue<int> q;//队列存放入度为0的顶点
for(int i = 0; i < numCourses; ++i){
if(indeg[i] == 0){
q.push(i);
}
}
while(!q.empty()){
auto it = q.front();
q.pop();
result.push_back(it);//取出来入度为0的顶点
for(int node : edge[it]){//遍历该顶点为起点的所有的边
indeg[node]--;//以该起点为顶点的所有的边所在的终点的入度减1
if(indeg[node] == 0)//若以该起点为顶点的所有的边所在的终点的入度为0
q.push(node);//放入队列中
}
}
if(result.size() == numCourses)//只有当result的结果与课程数量一致
return result;//才返回
return {};//否则该图存在环,无法完成学习
}
};