1. 程式人生 > 實用技巧 >演算法——課程表 II(有向圖拓撲排序)

演算法——課程表 II(有向圖拓撲排序)

現在你總共有 n 門課需要選,記為 0 到 n-1。
在選修某些課程之前需要一些先修課程。 例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用一個匹配來表示他們: [0,1]
給定課程總量以及它們的先決條件,返回你為了學完所有課程所安排的學習順序。
可能會有多個正確的順序,你只要返回一種就可以了。如果不可能完成所有課程,返回一個空陣列。
leetcode

解題思路:這是是個有向圖的拓撲排序問題。如果圖中存在環,那麼就不能產生結果,需要返回空。

  • 利用一個map來儲存圖,需要先學習的課程為出發點;
  • 深搜每個節點,一條路中,最後搜到的點需要放在最後。
  • 如果搜到了之前存在的節點,那麼就將失敗標記置位。
class Solution {
    Map<Integer, List<Integer>> map;
    boolean flag = true;
    int[] st;
    int[] res;
    int cnt;
    public int[] findOrder(int num, int[][] prerequisites) {
        map = new HashMap<>();
        res = new int[num];
        st = new int[num];
        cnt = num - 1;
        for(int i = 0; i < num; i++) map.put(i, new ArrayList<>());
        for(int[] p : prerequisites) map.get(p[1]).add(p[0]);


        for(int i = 0; i < num && flag; i++) {
            if(st[i] == 0) dfs(i);
        }

        if(flag) return res;

        return new int[0];
    }

    public void dfs(int cur) {
    	// 標記當前節點已經走過
        st[cur] = 1;

        for(int v : map.get(cur)) {
            if(st[v] == 0) {
            	// 如果點沒有被搜過
                dfs(v);
                if(!flag) return;
            }else if(st[v] == 1) {
            	// 如果搜到了走過的點,說明存在環
                flag = false;
                return;
            }
        }

		// 標記當前點已經完成搜尋,不在環上
        st[cur] = 2;
        res[cnt --] = cur;
        
    }
}