Leetcode 210. Course Schedule II

来源:互联网 发布:知乎b站三国演义 编辑:程序博客网 时间:2024/06/14 08:57

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

For example:

2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]

4, [[1,0],[2,0],[3,1],[3,2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].

Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
You may assume that there are no duplicate edges in the input prerequisites.

Hints:
This problem is equivalent to finding the topological order in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
Topological sort could also be done via BFS.
s思路:
1. 图的排序,那就是topological sort。有点忘了,这东西还得经常上手。回忆一下,竟然很快有答案了!
2. 先来dfs的topological sort。需要注意的是:topological sort值是对DAG(directed acyclic graph)有效。下图:用dfs的过程中,从3开始,先遍历上面的path,经过1,最后到0。0由于没有下家,没有下家,也就是说只有别人依靠他,他不依靠别人,那0就访问完了,把0的标志位设为2,表示访问完全,由于2不依靠任何人,所以可以把2放入vector中保存,然后退回到1,1只依靠0,现在也不依靠别人了,意味着1也访问完全,把1的标志设为2,再把1也放入vector中,然后继续回退到3。由于3除了依靠1,还和2连着,所以继续访问2,到2的时候,2继续访问2的下家,发现0,但此时查询2的状态是已经完全访问过,所以直接不管,回退到2,2现在也谁不靠,2的状态也可以设为完全访问了,同时把2也加入vector中,继续回退到3,此时的3已经把所有的下家都访问了一遍,也可以标记为完全访问,同时把3放入vector。现在,我们得到的vector是[0,1,2,3],这个顺序就是我们要求的topological sort顺序,也就是说排序的复杂度只有o(v+e)
这里写图片描述
3.现在再讨论一下用bfs如何实现topological sort?昨天讨论了用bfs检查是否有cycle时引入了in degree这个参量来表征图,in degree为0说明这个点是图的边缘的点,而且不在cycle中,而且没有其他点依赖他。把这个思路稍一扩展,便得到topological sort的bfs版本。仍以上图为例,分析如下:首先统计每个节点的入度,把入度为0的点放在queue里面,然后每次从queue取出一个节点,遍历这个节点的所有下家,把每个节点的入度都减1,表示拆掉这条edge,如果某次拆edge后,某个节点的入度也减少到0,说明也成了剩下的图的边缘节点,于是把这个节点加入到queue。这个过程目前为止还是和检查cycle一样,为了得到排序的vector,只需要发现某个节点入度为0时,无论是初始为0,或每次减1后变成0,就把这个节点放入vector,例如上图,放完所有节点后的vector就是[3,1,2,0]。我们发现这个顺序就是排序的顺序的逆序!
4. 编码的过程中,有一个值得注意的地方,逆序如何做?有两种方法,一是:reverse(v.begin(),v.end()),然后 return v;另一种,直接return vector < int>(v.rbegin(),v.rend())。后一种只需要一句代码就可以,但是要特别注意,容易错写成return vector < int>(v.end(),v.begin())。这样不正确的原因,是思维上没搞懂在stl里面,begin()表示第一个元素,而end()表示最后一个元素之后的位置,即:表示的是一个左闭右开的区间,所以end()什么元素都可能不指向,因此这样就不正确,但好在stl提供了rbegin()和rend(),方便逆向来获得iterator! 而这个错误,为什么值得认真面对呢?因为自己之前实现kd树排序的时候,把树分成两部分排序的时候,就没有搞清楚排序的序列的起始位置关系,没意识到stl操作的序列全都是[first,last)左闭右开的情况!!

//方法1:dfs,visited信息帮忙判断cycleclass Solution {public:    bool dfs(vector<vector<int>>&graph,vector<int>&visited,vector<int>&topsort,int i){        //        if(visited[i]==2) return true;        if(visited[i]==1) return false;        visited[i]=1;        for(int g:graph[i]){            if(!dfs(graph,visited,topsort,g)) return false;         }        visited[i]=2;        topsort.push_back(i);        return true;    }    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {        //        vector<vector<int>> graph(numCourses);        vector<int> visited(numCourses,0);        vector<int> topsort;        for(auto p:prerequisites){            graph[p.first].push_back(p.second);            }        for(int i=0;i<numCourses;i++){            if(!dfs(graph,visited,topsort,i)) return vector<int>(0);//bug:写成{}报错,正规的是写vector<int>(0),0个元素!          }        return topsort;    }};//方法1:bfs,in degree信息帮忙判断cycle.class Solution {public:    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {        //        vector<vector<int>> graph(numCourses);        vector<int> indegree(numCourses,0);        vector<int> topsort;        queue<int> qq;        for(auto p:prerequisites){            graph[p.first].push_back(p.second);              indegree[p.second]++;          }        for(int i=0;i<numCourses;i++){            if(indegree[i]==0) qq.push(i);        }        while(!qq.empty()){            int cur=qq.front();            topsort.push_back(cur);            qq.pop();            for(int&g:graph[cur]){                indegree[g]--;                if(indegree[g]==0) qq.push(g);            }           }        for(int i=0;i<numCourses;i++){            if(indegree[i]!=0) return vector<int>(0);        }        return vector<int>(topsort.rbegin(),topsort.rend());//注意:不能写成vector<int>(topsort.end(),topsort.begin())    }};
0 0
原创粉丝点击