拓扑排序
拓扑排序是一种基于有向图的遍历算法
因此对于简单题来说,就是对图的遍历加了顺序的要求,在使用dfs或bfs时稍加处理即可。
题目一
210. 课程表 II
思路
1.定义edges数组表示边
2.visited数组表示访问状态
3.要将节点的前导节点记录下来,表示有边相连。
3.进行遍历时,从每一个节点的出发,并visited[u]=1标记为访问中,不断往下遍历,直至为无先修课(称之为前导节点)将该节点入栈,回溯,期间若无未存储的前导节点时,该节点也该进栈了。若碰到的节点visited[]为1,为环,不可能存在拓扑排序。
代码
class Solution {
private:
vector<vector<int>>edges;//节点与节点的先后顺序以有向边进行存储
vector<int>visited;//表示节点的状态,搜索中,未搜索,已完成。
vector<int>result;
bool valid=true;
public:
void dfs(int u)
{
visited[u]=1;
for(int v:edges[u])
{
if(visited[v]==0)
{
dfs(v);
if(!valid)
{
return ;
}
}
else if(visited[v]==1)
{
valid=false;
return ;
}
}
visited[u]=2;
result.push_back(u);
}
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for(const auto& info:prerequisites)
{
edges[info[1]].push_back(info[0]);//将其前导节点存入其数组中,之后要对它们进行遍历并先入栈。
}
for(int i=0;i<numCourses&&valid;++i) 对每个节点的前导节点进行遍历。
{
if(!visited[i])
{
dfs(i);
}
}
if(!valid) 如果有环,不存在拓扑排序。
{
return{};
}
reverse(result.begin(),result.end());栈顶到栈尾就是该排序序列,但需将其首尾转置
return result;
}
};
原始题
链接
题目要求相同,上一题是该题的进阶版,但其实思路是一样的。
class Solution {
private:
vector<vector<int>>edges;
vector<int>visited;
bool valid=true;
public:
void dfs(int u)
{
visited[u]=1;
for(int v:edges[u])
{
if(visited[v]==0)
{
dfs(v);
if(!valid)
{
return ;
}
}
else if(visited[v]==1)
{
valid=false;
return ;
}
}
visited[u]=2;
}
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for(auto info:prerequisites)
{
edges[info[1]].push_back(info[0]);
}
for(int i=0;i<numCourses&&valid;++i)
{
if(!visited[i])
{
dfs(i);
}
}
return valid;
}
};
上一题更好的体现了(以栈的先进后出)进行拓扑排序的方法,以此得出正确的顺序。
而原始题更多的是考察若出现环便不能进行拓扑排序。