leetcode 207. 课程表
题目如下
数据范围
做题之前先搞清楚一个概念:拓扑序列
即在一个简单图内找一个入度为0的节点,
删除这个节点并删去与之相连接的边并把这条边连接的节点入度减一(如果存在)。
如此循环往复直到图内不存在节点我们认为拓扑序列存在。
那么在本题中参与课程的要求就是完成前一个课的内容,那么我们要开始第一个课程是不是要找不带前提的课程。即入度为0的课程,那么我们只要重复这个过程只要所有的课程上完了即所有的节点都删了就返回true否则返回false
通过代码(寻找拓扑序列直译版)
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> du(numCourses,0);
int count = 0;
// bool flag = false;
int t = -1;
for(int i = 0;i < prerequisites.size();i++){
du[prerequisites[i][1]]++;
}
while(true){
for(int i = 0;i < numCourses;i++){
if(t == -1 && du[i] == 0)t = i;
}
if(t == -1){
if(count == numCourses)return true;
return false;
}
du[t] = -1;
count++;
for(int i = 0;i < prerequisites.size();i++){
if(prerequisites[i][0] == t)du[prerequisites[i][1]]--;
}
t = -1;
}
if(count != numCourses)return false;
return true;
}
};
那么这个的缺点是什么呢?
显然每次要把入度为0对应的相关点的入度减1还有遍历一整个二维数组。
所以我们牺牲一些空间把每个节点对应相关点存起来就可以避免大量重复计算。
优化时间版
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> du(numCourses,0);
queue<int> q;
vector<vector<int>> aj(numCourses);
bool flag = false;
int n = prerequisites.size();
int count = 0;
int t = -1;
for(int i = 0;i < n;i++){
du[prerequisites[i][1]]++;
aj[prerequisites[i][0]].push_back(prerequisites[i][1]);
}
for(int i = 0;i < numCourses;i++){
if(du[i] == 0)q.push(i);
}
while(!q.empty()){
t = q.front();
q.pop();
count++;
for(int i = 0;i < aj[t].size();i++){
du[aj[t][i]]--;
if(du[aj[t][i]] == 0)q.push(aj[t][i]);
}
}
return count == numCourses;
}
};