1. 程式人生 > >LeetCode:課程表【207】

LeetCode:課程表【207】

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。這是不可能的。

說明:

  1. 輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣。詳情請參見圖的表示法
  2. 你可以假定輸入的先決條件中沒有重複的邊。

題目分析

  我們做這道題之前,需要先理解一個概念,就是拓撲排序。可以先參看這篇文章演算法:拓撲排序

  如果我們已經理解了拓撲排序,那麼這道題相對來說就比較簡單了。這道題的核心點是判斷有向圖是否有環

  存在下面這種情況的就返回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;
    }
}