首页 > 代码库 > leetcode 207. Course Schedule

leetcode 207. Course Schedule

https://leetcode.com/problems/course-schedule/#/description
图的算法题
题目就是求一堆课程有先修和后修的区别,这些课程能否构成拓扑排序而不矛盾;
应该算是我做的第一个关于图的算法题,一开始毫无思路,看了网上的sloutions,发现这道题还是比较简单的,可以用bfs和dfs都可以做。感觉还是比较典型的关于图算法例题。
http://www.cnblogs.com/zmyvszk/p/5573234.html
这个题解讲的还是比较明白的,虽然leetcode的题解也很明白,但是是英文,我看了也是讲的差不多。
 
bfs:
BFS:典型的拓扑排序。原理也很简单,在一个有向图中,每次找到一个没有前驱节点的节点(也就是入度为0的节点), * 然后把它指向其他节点的边都去掉,重复这个过程(BFS),直到所有节点已被找到,或者没有符合条件的节点(如果图中有环存在)
 
 
 1 vector<unordered_set<int>> makegraph(int numCourses, vector<pair<int, int>> prerequisites){
 2     vector<unordered_set<int>> graph(numCourses);
 3    for(auto pre:prerequisites) graph[pre.second].insert(pre.first);
 4    return graph;
 5 }
 6 vector<int> compute_degrees(vector<unordered_set<int>> graph){
 7    vector<int> degrees(graph.size(),0);
 8     for(auto n:graph)
 9        for(int neigh:n)
10           degrees[neigh]++;
11    return degrees;
12 }
13 bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
14    vector<unordered_set<int>> graph=makegraph(numCourses,prerequisites);
15    vector<int> degrees=compute_degrees(graph);
16    for(int i=0;i<numCourses;i++){
17      int j=0;
18      for(j;j<numCourses;j++)
19         if(!degrees[j]) break;
20      if(j==numCourses) return false;
21      degrees[j]=-1;
22      for(int neigh:graph[j])
23          degrees[neigh]--;
24     }
25    return true;
26   }
27 };

 

 
dfs
DFS的解法,也需要建立有向图,还是用二维数组来建立,和BFS不同的是,我们像现在需要一个一维数组visit来记录访问状态, * 大体思路是,先建立好有向图,然后从第一个门课开始,找其可构成哪门课,暂时将当前课程标记为已访问, * 然后对新得到的课程调用DFS递归,直到出现新的课程已经访问过了,则返回false,没有冲突的话返回true,然后把标记为已访问的课程改为未访问
 1 //dfs
 2 vector<unordered_set<int>> makegraph(int numCourses, vector<pair<int, int>>& prerequisites){
 3    vector<unordered_set<int>> graph(numCourses);
 4    for(auto pre:prerequisites)
 5       graph[pre.second].insert(pre.first);
 6    return graph;
 7 }
 8 bool dfscycle(vector<unordered_set<int>>& graph,int i,vector<bool>& onpath,vector<bool>& visit){
 9    if(visit[i]) return false;
10    visit[i]=onpath[i]=true;
11    for(int neigh:graph[i])
12        if(onpath[neigh]||dfscycle(graph,neigh,onpath,visit))
13           return true;
14     return onpath[i]=false;
15 }
16 bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
17     vector<unordered_set<int>> graph=makegraph(numCourses,prerequisites);
18     vector<bool> visit(numCourses,false),onpath(numCourses,false);
19     for(int i=0;i<numCourses;i++)
20        if(!visit[i]&&dfscycle(graph,i,onpath,visit))
21           return false;
22     return true;
23 }

 

 
在编写dfs code的时候,我发现一个很有趣的地方,之前在写函数的时候,如果不需要改变使用参数的值时,我尽量不用& 引用,担心不小心操作失误,改变了值,但是今天coding这道题的时候,由于建了一个图graph,我写函数的时候没用&,在输入量达到1000时,submission显示tle,当时我真是非常诧异,因为我跟solution写的大致相同,但我却tle了,后来查阅后发现,在函数时引用参数,是能提高程序效率的,尤其是当引用的参数非常大时,如一个图,用&提高程序效率,所以我上文中特地标了红色来提醒一下。
 
https://zhidao.baidu.com/question/149898386.html 百度上的解释
 
用引用肯定可以提高效率,不过要看情况,只有当引用的是占用“较大的内存空间的对象或结构体变量”时,才可能节约更多的时间。简单变量的引用不会节省空间。道理是这样的:
当实参是较大的对象或结构体变量时,如果直接传递给相应的函数形参,需要创建临时对象或结构本变量,而且还需要复制大块内存数据,这肯家比只传递一个“引用”(实际上是一种变形指针)要耗时得多。
如果你想测试的话,你应该构造“大点”的对象或结构体变量才行。
因为需要创建临时变量而拖累程序,而引用直接传递了地址。

leetcode 207. Course Schedule