课程表:
输入: 4, [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]
思路题解:
1、如果将每个课程看成一个节点,那么按照课程之间的关系,可以生成一个有向图,图的表示方法可以用邻接矩阵表示,即二维数组。
2、如果要生成一张可行的课程表,意味图着不能出现“环”;那么转化成有向图是否有环。
3、通过图的遍历,而图的遍历有BFS和DFS两种思路
法1:dfs,递归
class Solution {
public:
vector<vector<int>> edges;//
vector<int> visited;//visited[k]=0,1,2分别表示节点未被访问、访问中、已经访问
vector<int> res;//
bool vaild=true;
void dfs(int k){//dfs(k)判断从k节点出发,判断是否有环
visited[k]=1;//访问中
for(const auto&it:edges[k]){//依次遍历k课程的后续课程
if(visited[it]==0){
dfs(it);
if(vaild==false) return;
}else if(visited[it]==1){
vaild=false;return;
}
}
res.push_back(k);
visited[k]=2;//已访问过
}
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for(const auto&it:prerequisites){
edges[it[1]].push_back(it[0]);//edges[i]存储着课程i的以课程i为基础的后续课程
}
for(int i=0;i<numCourses&&vaild;i++){
if(visited[i]==0) dfs(i);//依次判断从各节点出发是否有“环”
}
if(vaild==false)
return {};
else{
reverse(res.begin(),res.end());//结果反转
return res;
}
}
};
法2:BFS,迭代
class Solution {
public:
vector<vector<int>> edges;
vector<int> indeg;
vector<int> res;
queue<int> q;
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
indeg.resize(numCourses);
for(const auto& info:prerequisites){
edges[info[1]].push_back(info[0]);
indeg[info[0]]++;
}
for(int i=0;i<numCourses;i++){
if(indeg[i]==0) q.push(i);
}
int visited=0;
while(!q.empty()){
int u=q.front();q.pop();
res.push_back(u);
visited++;
for(const auto& it:edges[u]){
indeg[it]--;
if(indeg[it]==0) q.push(it);
}
}
if(visited!=numCourses) res={};
return res;
}
};