LeetCode:課程表【207】
阿新 • • 發佈:2018-11-21
LeetCode:課程表【207】
題目描述
現在你總共有 n 門課需要選,記為 0
到 n-1
。
在選修某些課程之前需要一些先修課程。 例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用一個匹配來表示他們: [0,1]
給定課程總量以及它們的先決條件,判斷是否可能完成所有課程的學習?
示例 1:
輸入: 2, [[1,0]] 輸出: true 解釋: 總共有 2 門課程。學習課程 1 之前,你需要完成課程 0。所以這是可能的。
示例 2:
輸入: 2, [[1,0],[0,1]] 輸出: false 解釋: 總共有 2 門課程。學習課程 1 之前,你需要先完成課程 0;並且學習課程 0 之前,你還應先完成課程 1。這是不可能的。
說明:
- 輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請參見圖的表示法。
- 你可以假定輸入的先決條件中沒有重複的邊。
題目分析
我們做這道題之前,需要先理解一個概念,就是拓撲排序。可以先參看這篇文章演算法:拓撲排序。
如果我們已經理解了拓撲排序,那麼這道題相對來說就比較簡單了。這道題的核心點是判斷有向圖是否有環。
存在下面這種情況的就返回FALSE:
拓撲排序演算法如何判斷是否有環?
如上圖的右半部分所示,首先黑色是節點的預設顏色,我們把訪問到的節點標記為紅色,在遇到出度為0的第一個節點時,我們將它標記為藍色,最後所有的節點都會被染成藍色,說明這是一個合法的拓撲圖。
但是,在有環路的情況下,無論如何都無法到達出度為0的節點,當所有的黑色節點都變成紅色後,還沒有出現一個藍色,那說明就是有環。
所以,我們把黑色表示為0,藍色表示為1,紅色表示為2,遇到黑色節點很正常,遇到藍色節點也很正常(兩者都是正常的拓撲排序環節),但是當我們遇到紅色節點的時候說明遇到環路。
好了,說到這裡,我覺得已經很清楚了,實現細節請看程式碼。
Java題解
class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { ArrayList<ArrayList<Integer>> graph = new ArrayList<>(); for(int i=0;i<numCourses;i++) graph.add(new ArrayList<>()); for(int i=0;i<prerequisites.length;i++) { int course = prerequisites[i][0]; int pcourse = prerequisites[i][1]; graph.get(course).add(pcourse); } int[] visited = new int[numCourses]; for(int i=0;i<numCourses;i++) if(DFS(i,graph,visited)) return false; return true; } public boolean DFS(int curr,ArrayList<ArrayList<Integer>> graph,int[] visited) { //遞迴結束條件 if(visited[curr]==1)//這個節點已經被訪問 return true; if(visited[curr]==2)//這個節點沒有被訪問 return false; //業務邏輯處理 visited[curr]=1;//表示正在訪問 for(int id:graph.get(curr)) if(DFS(id,graph,visited)) return true; visited[curr]=2;//表示已經訪問 return false; } }