问题介绍
我理解主要是这么一个图论问题,在一群节点中,每个节点都有自己的入度和出度,一条有向边的方向可以理解为先后问题。而后我们对这些节点进行排序,保证先访问入度为0的节点。
主要是看有没有环的问题。
这样讲可能有些玄幻,举个例子。
课程表问题
在这个题目中,数组pre的first代表要想修1必须修0,即一条从0到1的有向边。
解法:广度优先
队列表示访问,入度为0的先访问(出队),访问到某一个节点之后,与其相邻节点的入度减一,如果减一之后出现新入度为0的节点,继续入队。
看最后访问数组的size和原数组是否相等
class Solution {
private:
vector<vector<int>> edges;//存储有向图
vector<int> in;//存储每个节点的入度
vector<int> ans;//返回符合条件的拓扑排序
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites)
{
edges.resize(numCourses);
in.resize(numCourses);
//用edges存储每个节点的出度(这样就知道与该节点相邻的所有节点),用in存储每个节点入度数目
for(const auto& info:prerequisites)
{
edges[info[1]].push_back(info[0]);
++in[info[0]];//被指向的节点入度+1
}
queue<int> q;
//将所有入度为0的节点入队
for(int i=0;i<numCourses;++i)
{
if(in[i]==0) q.push(i);
}
//每次取出队首元素,放入ans,并将所有与之相邻节点入度-1
while(!q.empty())
{
int first=q.front();
q.pop();
ans.emplace_back(first);
//遍历该节点所有出度,将相邻节点入度-1.如果此时新出现了入度为0的节点,入队
for(int v:edges[first])
{
--in[v];
if(in[v]==0) q.push(v);
}
}
//如果拓扑排序size小于原数组,则存在环
if(ans.size()!=numCourses) return {};
return ans;
}
};
至于深度优先,作者认为广度优先更符合人的正常思维一些,深度优先有些逆向思维,在面试的环境下掌握广度优先解即可。
最后,第207题,可作同解,也可略作优化,因为他只要t/f。我们可以省去ans数组,用一个数字来加法记录,可以节省空间;