【圖的遍歷】返回上課的順序 Course Schedule II

問題:express

There are a total of n courses you have to take, labeled from 0 to n - 1.ide

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]ui

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.spa

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.指針

For example:code

2, [[1,0]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1]遞歸

4, [[1,0],[2,0],[3,1],[3,2]]

There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].ip

Note:ci

  1. The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
  2. You may assume that there are no duplicate edges in the input prerequisites。

Hints:get

  1. This problem is equivalent to finding the topological order in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
  2. Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
  3. Topological sort could also be done via BFS.

解決:

① 與Course Schedule相同的思路,只是記錄下通過的節點的值。BFS,首先查找入度爲0 的端點,而後依次遍歷。

class Solution {//38ms
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] res = new int[numCourses];
        int p = 0;//指向結果的指針
        int len = prerequisites.length;//關係的長度
        if (numCourses == 0){
            return res;
        }
        if (len == 0){//沒有關係,直接返回結果
            for (int i = 0;i < numCourses;i ++){
                res[i] = i;
            }
            return res;
        }
        int[] in = new int[numCourses];//記錄節點的入度。
        for (int i = 0;i < len;i ++){//遍歷有向邊,初始化入度
            in[prerequisites[i][0]] ++;
        }
        Queue<Integer> queue = new LinkedList<>();//保存入度爲0的點
        for (int i = 0;i < numCourses;i ++){
            if (in[i] == 0){
                queue.offer(i);
            }
        }
        int count = queue.size();//記錄入度爲0的節點數
        while(! queue.isEmpty()){
            int top = queue.poll();
            res[p ++] = top;
            for (int i = 0;i < len;i ++){//將當前節點所指向的節點的入度-1
                if (prerequisites[i][1] == top){
                    in[prerequisites[i][0]] --;
                    if (in[prerequisites[i][0]] == 0){
                        count ++;
                        queue.offer(prerequisites[i][0]);
                    }
                }
            }
        }
        if (count == numCourses){
            return res;
        }else{
            return new int[0];
        }
    }
}

② dfs的解法。

class Solution { //14ms
    public static int[] findOrder(int numCourses, int[][] prerequisites) {
        Map<Integer,List<Integer>> adjacent = new HashMap<>();//記錄每個節點的相鄰節點
        boolean[] isvisited = new boolean[numCourses];//標記是否遍歷過
        boolean[] isonstack = new boolean[numCourses];//用來標記節點入棧
        List<Integer> list = new ArrayList<>();//用於存放結果
        for (int[] tmp : prerequisites){//添加相鄰節點
            if (! adjacent.containsKey(tmp[1])){
                List<Integer> t = new ArrayList<>();
                t.add(tmp[0]);
                adjacent.put(tmp[1],t);
            }else{
                adjacent.get(tmp[1]).add(tmp[0]);
            }
        }
        for (int i = 0;i < numCourses;i ++){//開始遍歷
            if (isvisited[i]) continue;//跳過已經遍歷過的節點
            if (dfs(adjacent,i,isvisited,isonstack,list)){//存在環
                return new int[0];
            }
        }
        int[] res = new int[list.size()];
        for (int i = 0;i < list.size();i ++){
            res[i] = list.get(i);
        }
        return res;
    }
    public static boolean dfs(Map<Integer,List<Integer>> adjacent,int i,boolean[] isvisited,
                       boolean[] isonstack,List<Integer> list){
        isvisited[i] = true;//遍歷當前節點
        isonstack[i] = true;//入棧
        if (adjacent.containsKey(i) && adjacent.get(i).size() > 0){//遍歷當前節點的子節點
            for (int j : adjacent.get(i)){//遞歸遍歷子節點
                if (! isvisited[j] && dfs(adjacent,j,isvisited,isonstack,list)) return true;//沒有遍歷過子節點而且子節點遞歸遍歷中存在環
                if (isonstack[j]) return true;//子節點已經存在於棧中,存在環
            }
        }
        list.add(0,i);//倒序從最後一個節點開始加入結果鏈表
        isonstack[i] = false;//出棧
        return false;//沒有環
    }
}

③ 在discuss中看到的效率最高的解法。。。

class Solution { //3ms     public int[] findOrder(int numCourses, int[][] prerequisites) {         int edge_len = prerequisites.length;         int[] edge = new int[prerequisites.length];         int[] edge_next = new int[prerequisites.length];         int[] last = new int [numCourses];         int[] indegree = new int[numCourses];         int mark = 0;         for (int i = 0;i < numCourses;i ++) last[i] = -1;         for (int i = 0;i < numCourses;i ++) indegree[i] = 0;         for (int i = 0;i < edge_len;i ++) {             edge[mark] = prerequisites[i][0];             indegree[prerequisites[i][0]] ++;             int x = prerequisites[i][1];             edge_next[mark] = last[x];             last[x] = mark;             mark ++;         }         int[] queue = new int [numCourses];         int l = -1, r= -1;         for (int i = 0;i < numCourses;i ++) {             if (indegree[i] == 0) queue[++ r] = i;         }         while (l < r) {             l ++;             int now = queue[l];             int edge_now = last[now];             while (edge_now != -1) {                 indegree[edge[edge_now]] --;                 if (indegree[edge[edge_now]] == 0)                     queue[++ r] = edge[edge_now];                 edge_now = edge_next[edge_now];             }         }         if (r + 1 != numCourses)             return new int[0];         else return queue;     } }  

相關文章
相關標籤/搜索