diff --git a/solutions/207. Course Schedule.md b/solutions/207. Course Schedule.md new file mode 100644 index 0000000..4b2bc35 --- /dev/null +++ b/solutions/207. Course Schedule.md @@ -0,0 +1,95 @@ +# [207. Course Schedule](https://leetcode.com/problems/course-schedule/) +# 思路 +仔细分析题目可知这道题的本质就是在有向图中检测环。而在有向图中检测环又可以看作是拓扑排序(不懂拓扑排序的童鞋可[参考此处](https://www.jianshu.com/p/b59db381561a))的应用. +拓扑排序又有两种基本思路: BFS和DFS. + +## BFS +BFS对有向无环图(DAG, Directed Acyclic Graph)进行拓扑排序的基本思路是: +1. 从DAG中选择一个 没有前驱(即入度为0)的顶点并输出; +2. 从DAG中删除该顶点和所有以它为起点的有向边; +3. 重复 1 和 2 直到当前的 DAG 图为空。 + +稍加改动即可判断有向图中是否存在环: +1. 先将所有入度(in degree)为0的顶点入栈(或队列); +2. 从栈顶取出一个元素并用count自加计数, 将所有以其为起点的边的终点的入度减1, 此时若该终点入度为0则入栈; +3. 栈非空时, 重复2; +4. 最后判断count是否等于图的顶点数, 若不相等则说明有环. + +为了方便找到以某个顶点为起点的所有边, 我们首先需要建一个二维数组G记录所有边, G[i]记录着以顶点i为起点的所有边的终点. DFS同. + +**时间复杂度分析:** +设图有n个顶点,e条边,在拓扑排序的过程中,搜索入度为零的顶点所需的时间是O(n)。 +在正常情况下,每个顶点进一次栈,出一次栈,所需时间O(n)。每个顶点入度减1的运算共执行了e次(若图基于邻接表)。所以总的时间复杂为O(n+e)。 + +## DFS +和常见的DFS一样, 我们需要一个一维数组 visited 来记录访问状态,但这里有三种状态: +* 0 表示还未访问过, 需要进一步调用递归函数; +* 1 表示已经访问了, 直接返回true即可; +* -1 表示正在访问, 表示遇到了两次, 有环, 返回false。 + +时间复杂度同BFS. + + +# C++ +## BFS +``` C++ +class Solution { +public: + bool canFinish(int numCourses, vector>& prerequisites) { + int arc_num = prerequisites.size(); + stackstk; + vectorin_degree(numCourses, 0); + vector>G(numCourses, vector{}); + + for(auto &arc : prerequisites){ // 建图 + in_degree[arc[0]]++; + G[arc[1]].push_back(arc[0]); + } + + for(int i = 0; i < numCourses; i++) // 先将所有入度为0的顶点入栈 + if(!in_degree[i]) stk.push(i); + + int count = 0; + while(!stk.empty()){ + int course = stk.top(); stk.pop(); + count++; + for(int c: G[course]){ // 所有以course为起点的边的终点 + if(!(--in_degree[c])) stk.push(c); + } + } + return count == numCourses; + } +}; +``` + ## DFS + ``` C++ + class Solution { +private: + bool DFS(vector>&G, vector& visited, int i) { + if (visited[i] == -1) return false; + if (visited[i] == 1) return true; + visited[i] = -1; + for (auto a : G[i]) { + if (!DFS(G, visited, a)) return false; + } + visited[i] = 1; + return true; + } +public: + bool canFinish(int numCourses, vector>& prerequisites) { + vector> G(numCourses, vector()); + vector visited(numCourses, 0); + + for (auto &arc : prerequisites) { + G[arc[1]].push_back(arc[0]); + } + + for (int i = 0; i < numCourses; ++i) + if (!DFS(G, visited, i)) return false; + + return true; + } +}; + ``` + +