210. 과정 일정 II

26227 단어 cppalgorithms

설명


numCourses에서 0까지 총 numCourses - 1개의 과정을 수강해야 합니다. prerequisites 배열이 제공됩니다. 여기서 prerequisites[i] = [ai, bi]는 과정을 수강하려면 먼저 과정bi을 수강해야 함을 나타냅니다.
  • 예를 들어 ai 쌍은 [0, 1] 과정을 수강하려면 먼저 0 과정을 수강해야 함을 나타냅니다.

  • 모든 과정을 마치기 위해 수강해야 하는 과정의 순서를 반환합니다. 유효한 답변이 많으면 그 중 하나를 반환합니다. 모든 과정을 완료할 수 없는 경우 빈 배열을 반환합니다.

    예 1:




    Input: numCourses = 2, prerequisites = [[1,0]]
    Output: [0,1]
    Explanation: 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].
    


    예 2:




    Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
    Output: [0,2,1,3]
    Explanation: 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].
    


    예 3:




    Input: numCourses = 1, prerequisites = []
    Output: [0]
    


    제약:


  • 1
  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • 모든 쌍ai != bi은 구체적입니다.



  • 솔루션



    솔루션 1



    직관



    DFS

    암호




    class Solution {
        private static final int WHITE = 1;
        private static final int GRAY = 2;
        private static final int BLACK = 3;
    
        boolean isPossible;
        Map<Integer, Integer> color;
        Map<Integer, List<Integer>> adjList;
        List<Integer> topologicalOrder;
    
        private void init(int numCourses) {
            isPossible = true;
            color = new HashMap<>(numCourses);
            adjList = new HashMap<>(numCourses);
            topologicalOrder = new ArrayList<>();
            // By default, all vertices are WHITE
            for (int i = 0; i < numCourses; i++) {
                color.put(i, WHITE);
            }
        }
    
        private void dfs(int node) {
            // Don't recurse further if we found a cycle already
            if (!isPossible) {
                return;
            }
            // Start the recursion
            color.put(node, GRAY);
            // Traverse on neighboring vertices
            for (Integer neighbor : adjList.getOrDefault(node, new ArrayList<>())) {
                if (color.get(neighbor) == WHITE) {
                    dfs(neighbor);
                } else if (color.get(neighbor) == GRAY) {
                    // An edge to a GRAY vertex represents a cycle
                    isPossible = false;
                }
            }
            // Recursion ends. We mark it as black
            color.put(node, BLACK);
            topologicalOrder.add(node);
        }
    
        public int[] findOrder(int numCourses, int[][] prerequisites) {
            init(numCourses);
            // Create the adjacency list representation of the graph
            for (int[] prerequisite : prerequisites) {
                int dest = prerequisite[0];
                int src = prerequisite[1];
                List<Integer> lst = adjList.getOrDefault(src, new ArrayList<>());
                lst.add(dest);
                adjList.put(src, lst);
            }
            // If the node is unprocessed, then call dfs on it.
            for (int i = 0; i < numCourses; i++) {
                if (color.get(i) == WHITE) {
                    dfs(i);
                }
            }
            int[] order;
            if (isPossible) {
                order = new int[numCourses];
                for (int i = 0; i < numCourses; i++) {
                    order[i] = topologicalOrder.get(numCourses - i - 1);
                }
            } else {
                order = new int[0];
            }
            return order;
        }
    }
    


    복잡성


  • 시간: O(V+E)
  • 스페이스: O(V+E)



  • 솔루션 2



    직관



    BFS

    암호




    class Solution {
        public int[] findOrder(int numCourses, int[][] prerequisites) {
    
            Map<Integer, List<Integer>> adjList = new HashMap<>();
            int[] indegree = new int[numCourses];
            int[] topologicalOrder = new int[numCourses];
    
            // Create the adjacency list representation of the graph
            for (int[] prerequisite : prerequisites) {
                int dest = prerequisite[0];
                int src = prerequisite[1];
                List<Integer> lst = adjList.getOrDefault(src, new ArrayList<Integer>());
                lst.add(dest);
                adjList.put(src, lst);
                // Record in-degree of each vertex
                indegree[dest] += 1;
            }
    
            // Add all vertices with 0 in-degree to the queue
            Queue<Integer> q = new LinkedList<Integer>();
            for (int i = 0; i < numCourses; i++) {
                if (indegree[i] == 0) {
                    q.add(i);
                }
            }
    
            int index = 0;
            // Process until the Q becomes empty
            while (!q.isEmpty()) {
                int node = q.remove();
                topologicalOrder[index++] = node;
                // Reduce the in-degree of each neighbor by 1
                if (adjList.containsKey(node)) {
                    for (Integer neighbor : adjList.get(node)) {
                        indegree[neighbor]--;
                        // If in-degree of a neighbor becomes 0, add it to the Q
                        if (indegree[neighbor] == 0) {
                            q.add(neighbor);
                        }
                    }
                }
            }
    
            // Check to see if topological sort is possible or not.
            if (index == numCourses) {
                return topologicalOrder;
            }
    
            return new int[0];
        }
    }
    



    class Solution {
    public:
        vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
            vector<vector<int>> g(numCourses);
            vector<int> in(numCourses, 0);
            for (auto& p : prerequisites) {
                int a = p[0], b = p[1];
                // b -> a
                g[b].push_back(a);
                // how many prerequisites need to learn a course?
                in[a] ++;
            }
    
            queue<int> q;
            // in = 0, means you've already finished the prerequisites, and you can learn this course
            for (int i = 0; i < numCourses; i++)
                if (in[i] == 0) q.push(i);
    
            vector<int> res;
            while (!q.empty()) {
                int p = q.front();
                q.pop();
                res.push_back(p);
                for (auto& c : g[p]) {
                    if (--in[c] == 0) q.push(c);
                }
            }
            if (res.size() == numCourses) return res;
            else return {};
        }
    };
    


    복잡성


  • 시간: O(V+E)
  • 스페이스: O(V+E)
  • 좋은 웹페이지 즐겨찾기