###### tags: `Leetcode` `medium` `graph` `topological sort` `dfs` `bfs` `python` `c++` # 210. Course Schedule II ## [題目連結:] https://leetcode.com/problems/course-schedule-ii/description/ ## 題目: There are a total of ```numCourses``` courses you have to take, labeled from ```0``` to ```numCourses - 1```. You are given an array ```prerequisites``` where ```prerequisites[i] = [ai, bi]``` indicates that you **must** take course ```bi``` first if you want to take course ```ai```. * For example, the pair ```[0, 1]```, indicates that to take course ```0``` you have to first take course ```1```. Return the ordering of courses you should take to finish all courses. If there are many valid answers, return **any** of them. If it is impossible to finish all courses, return **an empty array**. ## 解題想法: * 相同類型題目詳解: [207. Course Schedule](/txZn8rNCReWvEPygWnh-Zg) * 題目為,有幾堂課,並且有修課的先後順序,是否能修完所有課,若能修完,回傳任一課堂順序解,否則回傳空array * numCourses課數 * prerequisites[i] = [ai, bi] * 必須先修完修bi才能修ai * 本質為在**有向圖中檢查是否有環** ### **法1: 拓樸排序BFS** * Step1: 建立有向邊 * ex:[0,1],表示: 1->0 * Step2: 存所有indegree為0的點 * Step3: while每次選擇indegree為0的點加入最終res,刪掉該點連的所有邊 * 直到找不到-> 存在環 * 若剛好操作n次(n為節點數) -> 無環圖DAG(Directed Acyclic Graph) ## Python: BFS ``` python= from collections import defaultdict class Solution(object): def findOrder(self, numCourses, prerequisites): """ :type numCourses: int :type prerequisites: List[List[int]] :rtype: List[int] """ graph=defaultdict(list) indegrees=defaultdict(int) #connect the graph for v,u in prerequisites: graph[u].append(v) indegrees[v]+=1 visited=0 #已拜訪數量 res=[] zeroIndegree=[ node for node in range(numCourses) if indegrees[node]==0] while zeroIndegree: cur=zeroIndegree.pop() visited+=1 res.append(cur) #將鄰居的邊都刪掉 for neighber in graph[cur]: indegrees[neighber]-=1 if indegrees[neighber]==0: zeroIndegree.append(neighber) return res if visited==numCourses else [] numCourses = 4 prerequisites = [[1,0],[2,0],[3,1],[3,2]] result = Solution() ans = result.findOrder(numCourses,prerequisites) print(ans) ``` ## C++: BFS ``` cpp= class Solution { public: vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) { unordered_map<int, vector<int>> graph; unordered_map<int,int> indegrees; //init for (int i=0; i<numCourses; i++) indegrees[i]=0; //connect for (auto course: prerequisites){ graph[course[1]].push_back(course[0]); indegrees[course[0]]+=1; } //collect the node which has the zero indegrees stack<int> zeroIndegrees; for (int i=0; i<numCourses; i++){ if (indegrees[i]==0) zeroIndegrees.push(i); } int visited=0; vector<int> res; //bfs int curNode; while (!zeroIndegrees.empty()){ curNode=zeroIndegrees.top(); zeroIndegrees.pop(); visited+=1; res.push_back(curNode); for (auto neighber: graph[curNode]){ indegrees[neighber]-=1; if (indegrees[neighber]==0) zeroIndegrees.push(neighber); } } if (visited!=numCourses) res.clear(); return res; } }; ``` ### 法2: 拓樸排序DFS * Step1: 建立有向邊 * ex:[0,1],表示: 1->0 * Step2: 對於每點,設不同狀態進行判別 * 0 = Unknown * 1 = visiting * 2 = visited * Step3: 每次找到新點,判斷此點出發是否有環 * Step4: 子程式bool checkDAG()判斷當前點的拜訪狀態: ## Python: DFS ``` python= from collections import defaultdict class Solution(object): def findOrder(self, numCourses, prerequisites): """ :type numCourses: int :type prerequisites: List[List[int]] :rtype: List[int] """ graph = defaultdict(list) #連邊 for v,u in prerequisites: graph[u].append(v) #記錄點的目前狀態 0:尚未拜訪 1:仍在拜訪中 2:已完成拜訪 visited= [0]*numCourses path=[] for i in range(numCourses): if self.checkDAG(graph,visited,i,path)==False: return [] #有環 回傳空array return path[::-1] #因為最先返回的是最深層的 def checkDAG(self,graph,visited,cur_node,path): if visited[cur_node]==1: return False elif visited[cur_node]==2: return True else: visited[cur_node]=1 #拜訪鄰居 for node in graph[cur_node]: if self.checkDAG(graph,visited,node,path)==False: return False visited[cur_node]=2 path.append(cur_node) return True numCourses = 4 prerequisites = [[1,0],[2,0],[3,1],[3,2]] result = Solution() ans = result.findOrder(numCourses,prerequisites) print(ans) ``` ## C++: DFS ``` cpp= class Solution { public: vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) { unordered_map<int, vector<int>> graph; //connect for (auto course: prerequisites) graph[course[1]].push_back(course[0]); //init //0:unknown 1:visiting 2:visited vector<int> visited(numCourses,0); //dfs for (int i=0; i<numCourses; i++){ if (checkDAG(graph,visited,i)==false) return vector<int>(); } reverse(res.begin(), res.end()); return res; } bool checkDAG(unordered_map<int,vector<int>>& graph, vector<int>& visited, int curNode){ if (visited[curNode]==1) return false; else if (visited[curNode]==2) return true; else{ visited[curNode]=1; for (int neighber: graph[curNode]){ if (checkDAG(graph,visited,neighber)==false) return false; } visited[curNode]=2; res.push_back(curNode); return true; } } private: vector<int> res; }; ```