Open In App

Find Course Schedule II

Last Updated : 16 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given n courses, labeled from 0 to n - 1 and an array prerequisites[] where prerequisites[i] = [x, y] indicates that we need to take course y first if we want to take course x. Return the ordering of courses we should take to complete all courses. If there are multiple solutions, return any of them. If it is impossible to finish all courses, return an empty array.

Examples:

Input: n = 2, prerequisites[][] = [[1, 0]]
Output: [0, 1]
Explanation: To take course 1, you need to have finished course 0.
Thus, a valid order to take the courses is [0, 1].

Input: n = 4, prerequisites[][] = [[1, 0], [2, 0], [3, 1], [3, 2]]
Output: [0, 1, 2, 3] or [0, 2, 1, 3]
Explanation: To take course 3, you need to have finished both courses 1 and 2.
To take course 1 or course 2, you need to have finished course 0.
Thus, a valid order to take the courses is [0, 1, 2, 3] or [0, 2, 1, 3].

[Approach 1] Using Kahn's Algorithm - O(m+n) Time and O(m+n) Space

The problem can be solved using Kahn's Algorithm. The courses can be considered as nodes and the prerequisites can be considered as directed edges. Now, we can use Kahn's algorithm to find the topological sort of the courses. The topological sort is the order in which the courses can be completed.

Step-by-step algorithm:

  • Build the graph:
    • Use an adjacency list to symbolize the graph.
    • Use an array to track the in-degree for every node.
  • Topological Sort Using Kahn's Algorithm:
    • Use a queue to perform a breadth-first search (BFS).
    • Initialize the queue with nodes which have an in-degree of 0
    • Process every node by way of lowering the in-degree of its neighbors and append neighbors with an in-degree of zero to the queue.
  • Cycle Detection:
    • If the number of nodes processed does not equal the total number of courses, a cycle exists, and it's impossible to complete all courses.
C++
//Driver Code Starts
#include <bits/stdc++.h>
using namespace std;

vector<int> findOrder(int n, vector<vector<int>>& prerequisites) {
    
    // Initialize graph and in-degree array
    vector<vector<int>> adj(n);
    vector<int> inDegree(n, 0);
//Driver Code Ends


    // Build the graph
    for (auto& pre : prerequisites) {
        int dest = pre[0];
        int src = pre[1];
        adj[src].push_back(dest);
        inDegree[dest]++;
    }


//Driver Code Starts
    // Initialize the queue with 
    // courses having in-degree 0
    queue<int> q;
    for (int i = 0; i < n; i++) {
        if (inDegree[i] == 0) {
            q.push(i);
        }
    }

    vector<int> order;

    // Process nodes with BFS
    while (!q.empty()) {
        int current = q.front();
        q.pop();
        order.push_back(current);

        // Reduce in-degree for neighbors
        for (int neighbor : adj[current]) {
            inDegree[neighbor]--;
            if (inDegree[neighbor] == 0) {
                q.push(neighbor);
            }
        }
    }

    // Check if the topological sort 
    // is possible (i.e., no cycle)
    if (order.size() == n) {
        return order;
    } 
    
    return {}; 
    
}

int main() {
    int n = 4;
    vector<vector<int>> prerequisites = { {1, 0}, {2, 0}, {3, 1}, {3, 2} };

    vector<int> order = findOrder(n, prerequisites);

    for (int course : order) {
        cout << course << " ";
    }
    cout << endl;

    return 0;
}

//Driver Code Ends
Java
import java.util.*;

 class GfG {

     static ArrayList<Integer> findOrder(int n, int[][] prerequisites) {

        // Initialize adjacency list
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            adj.add(new ArrayList<>());
        }

        int[] inDegree = new int[n];

        // Build graph
        for (int[] pre : prerequisites) {
            int dest = pre[0];
            int src = pre[1];
            adj.get(src).add(dest);
            inDegree[dest]++;
        }

        // Queue for BFS
        Queue<Integer> q = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (inDegree[i] == 0) {
                q.add(i);
            }
        }

        ArrayList<Integer> order = new ArrayList<>();

        // Topological Sort using BFS
        while (!q.isEmpty()) {
            int current = q.poll();
            order.add(current);

            for (int neighbor : adj.get(current)) {
                inDegree[neighbor]--;
                if (inDegree[neighbor] == 0) {
                    q.add(neighbor);
                }
            }
        }

        // Return result only if all courses can be completed
        if (order.size() == n) {
            return order;
        }

        return new ArrayList<>();
    }

    public static void main(String[] args) {
        int n = 4;
        int[][] prerequisites = { {1, 0}, {2, 0}, {3, 1}, {3, 2} };

        ArrayList<Integer> result = findOrder(n, prerequisites);

        for (int course : result) {
            System.out.print(course + " ");
        }
        System.out.println();
    }
}
Python
# Python program to find the 
# course order for prerequisites

from collections import deque

def findOrder(n, prerequisites):
    
    # Initialize graph and in-degree array
    adj = [[] for _ in range(n)]
    inDegree = [0] * n

    # Build the graph
    for dest, src in prerequisites:
        adj[src].append(dest)
        inDegree[dest] += 1

    # Initialize the queue with 
    # courses having in-degree 0
    q = deque([i for i in range(n) if inDegree[i] == 0])

    order = []

    # Process nodes with BFS
    while q:
        current = q.popleft()
        order.append(current)

        # Reduce in-degree for neighbors
        for neighbor in adj[current]:
            inDegree[neighbor] -= 1
            if inDegree[neighbor] == 0:
                q.append(neighbor)

    # Check if the topological sort 
    # is possible (i.e., no cycle)
    if len(order) == n:
        return order
    
    return []

if __name__ == "__main__":
    n = 4
    prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]]

    order = findOrder(n, prerequisites)

    print(" ".join(map(str, order)))
C#
// C# program to find the course order for prerequisites

using System;
using System.Collections.Generic;

class GfG {

    static List<int> findOrder(int n, List<List<int>> prerequisites) {
        
        // Initialize graph and in-degree array
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i < n; i++) {
            adj.Add(new List<int>());
        }
        int[] inDegree = new int[n];

        // Build the graph
        foreach (var pre in prerequisites) {
            int dest = pre[0];
            int src = pre[1];
            adj[src].Add(dest);
            inDegree[dest]++;
        }

        // Initialize the queue with 
        // courses having in-degree 0
        Queue<int> q = new Queue<int>();
        for (int i = 0; i < n; i++) {
            if (inDegree[i] == 0) {
                q.Enqueue(i);
            }
        }

        List<int> order = new List<int>();

        // Process nodes with BFS
        while (q.Count > 0) {
            int current = q.Dequeue();
            order.Add(current);

            // Reduce in-degree for neighbors
            foreach (int neighbor in adj[current]) {
                inDegree[neighbor]--;
                if (inDegree[neighbor] == 0) {
                    q.Enqueue(neighbor);
                }
            }
        }

        // Check if the topological sort 
        // is possible (i.e., no cycle)
        if (order.Count == n) {
            return order;
        } 
        
        return new List<int>(); 
    }

    static void Main(string[] args) {
        int n = 4;
        List<List<int>> prerequisites = new List<List<int>> {
            new List<int> { 1, 0 },
            new List<int> { 2, 0 },
            new List<int> { 3, 1 },
            new List<int> { 3, 2 }
        };

        List<int> order = findOrder(n, prerequisites);

        Console.WriteLine(string.Join(" ", order));
    }
}
JavaScript
// JavaScript program to find 
// the course order for prerequisites

function findOrder(n, prerequisites) {
    
    // Initialize graph and in-degree array
    const adj = Array.from({ length: n }, () => []);
    const inDegree = Array(n).fill(0);

    // Build the graph
    for (const [dest, src] of prerequisites) {
        adj[src].push(dest);
        inDegree[dest]++;
    }

    // Initialize the queue with 
    // courses having in-degree 0
    const q = [];
    for (let i = 0; i < n; i++) {
        if (inDegree[i] === 0) {
            q.push(i);
        }
    }

    const order = [];

    // Process nodes with BFS
    while (q.length > 0) {
        const current = q.shift();
        order.push(current);

        // Reduce in-degree for neighbors
        for (const neighbor of adj[current]) {
            inDegree[neighbor]--;
            if (inDegree[neighbor] === 0) {
                q.push(neighbor);
            }
        }
    }

    // Check if the topological sort 
    // is possible (i.e., no cycle)
    return order.length === n ? order : [];
}

const n = 4;
const prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]];

const order = findOrder(n, prerequisites);

console.log(order.join(" "));

Output
0 1 2 3 

Time Complexity: O(n+m), where n is the number of courses and m is the size of prerequisite array .
Auxiliary Space: O(n+m)

[Approach 2] Using DFS - O(m+n) Time and O(m+n) Space

DFS is used in this task ordering problem because it naturally supports topological sorting by recursively visiting each task’s dependencies before marking the task itself as complete. This ensures that every prerequisite is processed before the current task, helping to build a valid order. Additionally, DFS makes it easy to detect cycles by tracking the visitation state of each node—if we revisit a node that is still being explored (marked as "visiting"), a cycle exists, and no valid order is possible. Once all dependencies of a task have been visited, the task is added to a stack, which, when reversed, gives the correct topological order of tasks.

C++
#include <bits/stdc++.h>
using namespace std;

bool dfs(int node, vector<vector<int>>& adj, 
                vector<int>& visited, vector<int>& stack) {
    
    // mark as visiting
    visited[node] = 1; 

    for (int neighbor : adj[node]) {
        if (visited[neighbor] == 1) {
            
            // cycle detected
            return false; 
        } else if (visited[neighbor] == 0) {
            if (!dfs(neighbor, adj, visited, stack)) {
                
                // cycle in deeper recursion
                return false; 
            }
        }
    }
    
    // mark as visited
    visited[node] = 2; 
    stack.push_back(node);
    return true;
}

vector<int> findOrder(int n, vector<vector<int>>& prerequisites) {
    vector<vector<int>> adj(n);
    for (auto& pre : prerequisites) {
        int dest = pre[0];
        int src = pre[1];
        adj[src].push_back(dest);
    }
    
     // 0 = unvisited, 1 = visiting, 2 = visited
    vector<int> visited(n, 0);
    vector<int> stack;

    for (int i = 0; i < n; i++) {
        if (visited[i] == 0) {
            if (!dfs(i, adj, visited, stack)) {
                
                // cycle detected
                return {}; 
            }
        }
    }
    
    // reverse stack to get correct order
    reverse(stack.begin(), stack.end()); 
    return stack;
}

int main() {
    int n = 4;
    vector<vector<int>> prerequisites = { {1, 0}, {2, 0}, {3, 1}, {3, 2} };

    vector<int> order = findOrder(n, prerequisites);

        for (int course : order) {
            cout << course << " ";
        }
        cout << endl;

    return 0;
}
Java
import java.util.*;

 class GfG {

     static boolean dfs(int node, ArrayList<ArrayList<Integer>> adj,
                               int[] visited, ArrayList<Integer> stack) {
        
        // mark as visiting
        visited[node] = 1; 

        for (int neighbor : adj.get(node)) {
            if (visited[neighbor] == 1) {
                
                // cycle detected
                return false; 
            } else if (visited[neighbor] == 0) {
                if (!dfs(neighbor, adj, visited, stack)) {
                    
                    // cycle in deeper recursion
                    return false; 
                }
            }
        }
        
        // mark as visited
        visited[node] = 2; 
        stack.add(node);
        return true;
    }

    public static ArrayList<Integer> findOrder(int n, int[][] prerequisites) {
        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
        for (int i = 0; i < n; i++) adj.add(new ArrayList<>());

        for (int[] pre : prerequisites) {
            int dest = pre[0];
            int src = pre[1];
            adj.get(src).add(dest);
        }

        int[] visited = new int[n];
        ArrayList<Integer> stack = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            if (visited[i] == 0) {
                if (!dfs(i, adj, visited, stack)) {
                    
                    // cycle detected
                    return new ArrayList<>(); 
                }
            }
        }
        
        // reverse to get the correct order
        Collections.reverse(stack); 
        return stack;
    }

    public static void main(String[] args) {
        int n = 4;
        int[][] prerequisites = { {1, 0}, {2, 0}, {3, 1}, {3, 2} };

        ArrayList<Integer> order = findOrder(n, prerequisites);

        for (int course : order) {
            System.out.print(course + " ");
        }
        System.out.println();
    }
}
Python
def dfs(node, adj, visited, stack):
    
    # mark as visiting
    visited[node] = 1

    for neighbor in adj[node]:
        if visited[neighbor] == 1:
            
            # cycle detected
            return False
        elif visited[neighbor] == 0:
            if not dfs(neighbor, adj, visited, stack):
                
                # cycle in deeper recursion
                return False

    # mark as visited
    visited[node] = 2
    stack.append(node)
    return True

def findOrder(n, prerequisites):
    adj = [[] for _ in range(n)]
    for pre in prerequisites:
        dest, src = pre
        adj[src].append(dest)
    
     # 0 = unvisited, 1 = visiting, 2 = visited
    visited = [0] * n 
    stack = []

    for i in range(n):
        if visited[i] == 0:
            if not dfs(i, adj, visited, stack):
                
                # cycle detected
                return []

    # reverse stack to get correct order
    stack.reverse()
    return stack

if __name__ == "__main__":
    n = 4
    prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]]

    order = findOrder(n, prerequisites)

    for course in order:
        print(course, end=" ")
    print()
C#
using System;
using System.Collections.Generic;

class GfG {
    
    // DFS to detect cycle and find topological order
    static bool dfs(int node, List<List<int>> adj,
                         int[] visited, List<int> stack) {
                             
        // mark as visiting
        visited[node] = 1; 

        foreach (int neighbor in adj[node]) {
            // cycle detected
            if (visited[neighbor] == 1) 
                return false;
            else if (visited[neighbor] == 0)
            {
                // cycle in deeper recursion
                if (!dfs(neighbor, adj, visited, stack)) 
                    return false;
            }
        }

        visited[node] = 2; // mark as visited
        stack.Add(node);
        return true;
    }

    // Function to find the topological order
    static List<int> findOrder(int n, int[,] prerequisites) {
        
        // Adjacency list for the graph
        var adj = new List<List<int>>(n);
        for (int i = 0; i < n; i++)
            adj.Add(new List<int>());

        // Fill the adjacency list from prerequisites
        for (int i = 0; i < prerequisites.GetLength(0); i++)
        {
            int dest = prerequisites[i, 0];
            int src = prerequisites[i, 1];
            adj[src].Add(dest);
        }

        // Visited array (0 = unvisited, 1 = visiting, 2 = visited)
        var visited = new int[n];
        var stack = new List<int>();

        // Perform DFS for each node
        for (int i = 0; i < n; i++) {
            if (visited[i] == 0) {
                if (!dfs(i, adj, visited, stack)) {
                    
                    // Cycle detected
                    return new List<int>();
                }
            }
        }

        // Reverse the stack to get the correct order
        stack.Reverse();
        return stack;
    }

    static void Main() {
        
        int n = 4;
        int[,] prerequisites = { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 3, 2 } };

        var order = findOrder(n, prerequisites);

        // Output the result
        foreach (var course in order) {
            Console.Write(course + " ");
        }
        Console.WriteLine();
    }
}
JavaScript
function dfs(node, adj, visited, stack) {
    
    // mark as visiting
    visited[node] = 1;

    for (let neighbor of adj[node]) {
        if (visited[neighbor] === 1) {
            
            // cycle detected
            return false;
        } else if (visited[neighbor] === 0) {
            if (!dfs(neighbor, adj, visited, stack)) {
                
                // cycle in deeper recursion
                return false;
            }
        }
    }

    // mark as visited
    visited[node] = 2;
    stack.push(node);
    return true;
}

function findOrder(n, prerequisites) {
    let adj = Array.from({ length: n }, () => []);
    for (let pre of prerequisites) {
        let dest = pre[0];
        let src = pre[1];
        adj[src].push(dest);
    }

    // 0 = unvisited, 1 = visiting, 2 = visited
    let visited = new Array(n).fill(0);
    let stack = [];

    for (let i = 0; i < n; i++) {
        if (visited[i] === 0) {
            if (!dfs(i, adj, visited, stack)) {
                
                // cycle detected
                return [];
            }
        }
    }

    // reverse stack to get correct order
    return stack.reverse();
}

function main() {
    let n = 4;
    let prerequisites = [
        [1, 0],
        [2, 0],
        [3, 1],
        [3, 2]
    ];

    let order = findOrder(n, prerequisites);

    console.log(order.join(" "));
}

main();

Output
0 2 1 3 



Practice Tags :

Similar Reads