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(" "));
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();
Similar Reads
CSES Solutions â Course Schedule You have to complete n courses. There are m requirements of form "course a has to be completed before course b". Your task is to find an order in which you can complete the courses. Examples: Input: n = 5, m = 3, requirements[][] = {{1, 2}, {3, 1}, {4, 5}}Output: 3 4 1 5 2Explanation: Since course 3
7 min read
Scheduling in Greedy Algorithms In this article, we will discuss various scheduling algorithms for Greedy Algorithms. Many scheduling problems can be solved using greedy algorithms. Problem statement: Given N events with their starting and ending times, find a schedule that includes as many events as possible. It is not possible t
2 min read
Assembly Line Scheduling | DP-34 Assembly line scheduling is a manufacturing problem. In automobile industries assembly lines are used to transfer parts from one station to another station. - Manufacturing of large items like car, trucks etc. generally undergoes through multiple stations, where each station is responsible for assem
15+ min read
Find the ordering of task from given dependencies (Course Schedule II) Given a total of N tasks that you have to pick, labelled from 0 to N-1. Some tasks may have prerequisite tasks, for example, to pick task 0 you have to first finish task 1, which is expressed as a pair: [0, 1] Given the total number of tasks and a list of prerequisite pairs, return the ordering of t
15 min read
Find the ordering of task from given dependencies (Course Schedule II) Given a total of N tasks that you have to pick, labelled from 0 to N-1. Some tasks may have prerequisite tasks, for example, to pick task 0 you have to first finish task 1, which is expressed as a pair: [0, 1] Given the total number of tasks and a list of prerequisite pairs, return the ordering of t
15 min read
Find the ordering of task from given dependencies (Course Schedule II) Given a total of N tasks that you have to pick, labelled from 0 to N-1. Some tasks may have prerequisite tasks, for example, to pick task 0 you have to first finish task 1, which is expressed as a pair: [0, 1] Given the total number of tasks and a list of prerequisite pairs, return the ordering of t
15 min read