[LeetCode] 210. 课程表II
题目描述:
现在你总共有 numCourses
门课需要选,记为 0
到 numCourses - 1
。给你一个数组 prerequisites
,其中 prerequisites[i] = [ai, bi]
,表示在选修课程 ai
前 必须 先选修 bi
。
- 例如,想要学习课程
0
,你需要先完成课程1
,我们用一个匹配来表示:[0,1]
。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]] 输出:[0,1] 解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为[0,1] 。
示例 2:
输入:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]] 输出:[0,2,1,3] 解释:总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。 因此,一个正确的课程顺序是 [0,1,2,3]。另一个正确的排序是[0,2,1,3]。
示例 3:
输入:numCourses = 1, prerequisites = [] 输出:[0]
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= numCourses * (numCourses - 1)
prerequisites[i].length == 2
0 <= ai, bi < numCourses
ai != bi
- 所有
[ai, bi]
互不相同
题目链接:
. - 力扣(LeetCode)
解题主要思路:
其实这道题跟 "课程表" 几乎没差别,唯一的差别就是一个是返回属否合理,一个是返回排序结果。
经典的bfs拓扑排序题,先借助stl容器将有向图和节点对应的入度记录下来,接着先将入度为0的节点入队列,当队列不为空时循环进行以下操作:
1. 提取头节点,将该节点存入ret数组中,并且对该节点的相邻节点去边
2.判断邻居节点的入度是否为0,若为0则加入到队列中
最后再判断ret数组的size是否等于numCourses,如果等于,说明合理且能排序出结果;如果不等于,说明无法排序完全部课程并且返回一个空数组。
解题代码:
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> ret;
ret.reserve(numCourses); // 提前开好空间并且不进行初始化
vector<vector<int>> edges(numCourses); // 邻接表
vector<int> in(numCourses); // 统计对应节点的入度
// 建图
for (auto& e : prerequisites) {
int a = e[0], b = e[1]; // b --> a
edges[b].push_back(a);
++in[a];
}
// 找到入度为0的节点,加入队列中
queue<int> que;
for (int i = 0; i < numCourses; ++i) {
if (in[i] == 0) que.push(i);
}
// bfs
while (!que.empty()) {
// 提取头节点
int front = que.front(); que.pop();
ret.push_back(front);
// 相邻节点去边
for (auto& e : edges[front]) {
--in[e];
if (in[e] == 0) que.push(e);
}
}
if (ret.size() == numCourses) return ret;
else return {};
}
};