207. Course Schedule
仅供自己学习
思路:
题目给出的 prerequisites 实际可以转化为一个有向图,那么既然有明确的先后顺序排列才能完成课程学习,这就要求这组数据组成的图不能是有向有环图,所以应该往DFS和BFS想,只要搜索整张图没有发现环,那么就可以输出true,否则输出false。按照题目所说,prerequisites[1]是指向prerequisites[0]的。上述也就是一种拓扑排序,即当有向图中的任意一条边(u,v),u都在v前的排列,则该排列就是有向图的拓扑排序。
DFS:此时结点可能会有三个状态,未探索,探索中,探索完成,分别用 0,1,2代替,并且用一维向量visited存储状态,因为转化为有向图的时候prerequisites[1]才是出度边起始的节点,所以还需用一个edge的二维数组存储prerequisites[0] [1]交换后的位置,这样就可以得到每个节点的邻居结点,便于算法执行。之后便遍历每个节点并且判断是否为未探索并且不成环,是则DFS,否则如果不成环则继续下一个点,如果成环则直接return false。进入DFS后,先令该点为探索中的状态,在遍历该点的邻接点,判断是否为0,是则继续DFS,否则是探索中的状态则判断为成环,此时就return一直结束DFS,并且直接return false,否则是探索完成则换另一个邻居点继续DFS。
因为我们只需要判断是否存在这样一个拓扑排序,所以并不需要一个栈去存储拓扑排序的结果
代码:
1 class Solution { 2 public: 3 vector<vector<int>> edge; 4 vector<int> visited; 5 bool valid=true; 6 7 void dfs(int u){ 8 visited[u]=1; 9 for(int v:edge[u]){ 10 if(visited[v]==0){ 11 dfs(v); 12 if(!valid) return; 13 } 14 else if(visited[v]==1){ 15 valid=false; 16 return; 17 } 18 } 19 visited[u]=2; 20 } 21 22 bool canFinish(int numCourses, vector<vector<int>>& prerequisites) { 23 edge.resize(numCourses); 24 visited.resize(numCourses); 25 for(const auto& exc:prerequisites){ 26 edge[exc[1]].push_back(exc[0]); //构建边的结构,存储一个结点,他的邻居结点是存于嵌套vector中 27 } 28 for(int i=0;i<numCourses&&valid;++i){ 29 if(!visited[i]) 30 dfs(i); 31 } 32 return valid; 33 } 34 };
BFS:如果要使用BFS,首先就要解决如何变型传统的BFS使其具有判断成环的功能,这里考虑的是搜索入度边为0的结点,只把入度边为0的结点加入到队列,每次搜索一个邻居节点就把该邻居结点的这条入度边删除,即indeg[i] --,只要删除入度边后该结点入度边为0就加入进队列。如果没有入度边为0,那么就会存在环。同时我们计数探索过的节点数,只要这个数等于课程数,那么就能返回true 否则返回false
代码:
1 class Solution { 2 public: 3 vector<vector<int>> edge; 4 vector<int> indeg; 5 bool canFinish(int numCourses, vector<vector<int>>& prerequisites) { 6 edge.resize(numCourses); 7 indeg.resize(numCourses); 8 for(const auto& v:prerequisites){ 9 edge[v[1]].push_back(v[0]); 10 ++indeg[v[0]]; //给每个结点计数入度边 11 } 12 queue<int> q; 13 for(int i=0;i<numCourses;++i){ //第一次将入度边为0的结点加入进队列 14 if(indeg[i]==0) 15 q.push(i); 16 } 17 int visited=0; //用来计数探索过的节点数 18 while(!q.empty()){ 19 ++visited; 20 int temp=q.front(); 21 q.pop(); 22 for(auto& u:edge[temp]){ //每次探索一个邻居结点 23 --indeg[u]; //并减掉该入度边 24 if(indeg[u]==0) //只要该点入度边为0就加入队列 25 q.push(u); 26 } 27 } 28 return visited == numCourses; 29 } 30 };

浙公网安备 33010602011771号