课程表

思路
1、拓扑排序加广度优先遍历
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
std::unordered_map<int, std::vector<int>> map; // 字典用于记录某门前置课程,以及依赖它才能修的课程(出边)
int sz = prerequisites.size();
std::vector<int> pre; // 用于记录某门课程的入度,就是需要修几门必修课,才能修当前这门课。
pre.resize(numCourses, 0);
// 构建字典和入度表
for(int i = 0; i < sz; ++i) {
pre[prerequisites[i][0]] += prerequisites[i].size() - 1; // 注意这里输入数据有这种[[0,1],[0,2]],遍历的时候应该是累加
for (int j = 1; j < prerequisites[i].size(); ++j) {
auto iter = map.find(prerequisites[i][j]);//寻找字典中,以该门课作为前置课程,是否已经存在了。
if (iter != map.end()) {
auto& tmp_vec = iter->second;//注意这里用引用,避免复制构造,可以提高性能
tmp_vec.push_back(prerequisites[i][0]); // 这里可以直接放入,对于两个节点之间入度边只可能有一条不会冲突
} else {
std::vector<int> tmp_vec {prerequisites[i][0]};
map[prerequisites[i][j]] = tmp_vec;
}
}
}
// 拓扑排序
std::queue<int> q;
// 寻找入度为0的节点,不需要前置课程,直接放入
for (int i = 0; i < numCourses; ++i) {
if (0 == pre[i]) {
q.push(i);
}
}
std::vector<int> res;
while (!q.empty()) {// 当队列为空时就结束,说明的能修的已进修过了
int foo = q.front();
q.pop();
auto iter = map.find(foo);
if(iter != map.end()) {
auto vec = iter->second;
for(auto& it : vec) {
pre[it] -= 1;
if (pre[it] == 0) { // 注意这里为0即可,判断条件 <=也是成立的
q.push(it);
}
}
}
res.push_back(foo);
}
// 判断是否还有课程中存在前置课程,如果有说明该课程不能修,返回空
for (int i = 0; i < numCourses; ++i) {
if(pre[i] > 0) {
return std::vector<int>();
}
}
return res;
}

浙公网安备 33010602011771号