Open In App

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 tasks you should pick to finish all tasks. There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all tasks, return an empty array. 

Examples:



Input: N=2, Prerequisite_Pairs=[[1, 0]]
Output: [0, 1] 
Explanation: There are a total of 2 tasks to pick. To pick task 1 you should have finished task 0. So the correct task order is [0, 1] . 

Input: N=4, Prerequisite_Pairs=[[1, 0], [2, 0], [3, 1], [3, 2]] 
Output: [0, 1, 2, 3] or [0, 2, 1, 3] 
Explanation: There are a total of 4 tasks to pick. To pick task 3 you should have finished both tasks 1 and 2. Both tasks 1 and 2 should be pick after you finished task 0. So one correct task order is [0, 1, 2, 3]. Another correct ordering is [0, 2, 1, 3].



Find the ordering of task from given dependencies using Topological Sorting using BFS:

Consider the Problem as a graph. All tasks are nodes of the graph and if task u is a prerequisite of task v, we will add a directed edge from node u to node v. Now, this problem is equivalent to finding a topological ordering of nodes/tasks (using topological sorting) in the graph represented by prerequisites. If there is a cycle in the graph, then it is not possible to finish all tasks. Here we use Kahn’s algorithm for topological sorting

Follow the steps to solve this problem:

Below is the implementation of above approach:




// CPP program to find order to process tasks
// so that all tasks can be finished. This program
// mainly uses Kahn's algorithm.
#include <bits/stdc++.h>
using namespace std;
 
// Returns adjacency list representation of graph from
// given set of pairs.
vector<vector<int> > make_graph(int numTasks,
            vector<pair<int, int> >& prerequisites)
{
    vector<vector<int> > graph(numTasks);
    for (auto pre : prerequisites)
        graph[pre.second].push_back(pre.first);
    return graph;
}
 
// Computes in-degree of every vertex
vector<int> compute_indegree(vector<vector<int> >& graph)
{
    vector<int> degrees(graph.size(), 0);
    for (auto neighbors : graph)
        for (int neigh : neighbors)
            degrees[neigh]++;
    return degrees;
}
 
// main function for topological sorting
vector<int> findOrder(int numTasks,
        vector<pair<int, int> >& prerequisites)
{
    // Create an adjacency list
    vector<vector<int> > graph =
            make_graph(numTasks, prerequisites);
 
    // Find vertices of zero degree
    vector<int> degrees = compute_indegree(graph);
    queue<int> zeros;
    for (int i = 0; i < numTasks; i++)
        if (!degrees[i])
            zeros.push(i);
 
    // Find vertices in topological order
    // starting with vertices of 0 degree
    // and reducing degrees of adjacent.
    vector<int> toposort;
    for (int i = 0; i < numTasks; i++) {
        if (zeros.empty())
            return {};
        int zero = zeros.front();
        zeros.pop();
        toposort.push_back(zero);
        for (int neigh : graph[zero]) {
            if (!--degrees[neigh])
                zeros.push(neigh);
        }
    }
    return toposort;
}
 
// Driver code
int main()
{
    int numTasks = 4;
    vector<pair<int, int> > prerequisites;
 
    // for prerequisites: [[1, 0], [2, 1], [3, 2]]
 
    prerequisites.push_back(make_pair(1, 0));
    prerequisites.push_back(make_pair(2, 1));
    prerequisites.push_back(make_pair(3, 2));
    vector<int> v = findOrder(numTasks, prerequisites);
 
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
 
    return 0;
}




// Java program to find order to process tasks
// so that all tasks can be finished. This program
// mainly uses Kahn's algorithm.
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
 
public class Dep {
 
    // Returns adjacency list representation of graph from
    // given set of pairs.
    static ArrayList<HashSet<Integer> >
    make_graph(int numTasks, int[][] prerequisites)
    {
        ArrayList<HashSet<Integer> > graph
            = new ArrayList<HashSet<Integer>>(numTasks);
        for (int i = 0; i < numTasks; i++)
            graph.add(new HashSet<Integer>());
        for (int[] pre : prerequisites)
            graph.get(pre[1]).add(pre[0]);
        return graph;
    }
 
    // Computes in-degree of every vertex
    static int[] compute_indegree(
        ArrayList<HashSet<Integer> > graph)
    {
        int[] degrees = new int[graph.size()];
        for (HashSet<Integer> neighbors : graph)
            for (int neigh : neighbors)
                degrees[neigh]++;
        return degrees;
    }
 
    // main function for topological sorting
    static ArrayList<Integer>
    findOrder(int numTasks, int[][] prerequisites)
    {
        // Create an adjacency list
        ArrayList<HashSet<Integer> > graph
            = make_graph(numTasks, prerequisites);
 
        // Find vertices of zero degree
        int[] degrees = compute_indegree(graph);
        Queue<Integer> zeros = new LinkedList<Integer>();
        for (int i = 0; i < numTasks; i++)
            if (degrees[i] == 0)
                zeros.add(i);
 
        // Find vertices in topological order
        // starting with vertices of 0 degree
        // and reducing degrees of adjacent.
        ArrayList<Integer> toposort
            = new ArrayList<Integer>();
        for (int i = 0; i < numTasks; i++) {
            if (zeros.isEmpty())
                return new ArrayList<Integer>();
            int zero = zeros.peek();
            zeros.poll();
            toposort.add(zero);
            for (int neigh : graph.get(zero)) {
                if (--degrees[neigh] == 0)
                    zeros.add(neigh);
            }
        }
        return toposort;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int numTasks = 4;
        int[][] prerequisites
            = { { 1, 0 }, { 2, 1 }, { 3, 2 } };
 
        ArrayList<Integer> v
            = findOrder(numTasks, prerequisites);
 
        for (int i = 0; i < v.size(); i++) {
            System.out.print(v.get(i) + " ");
        }
    }
}
 
// This code is contributed by Lovely Jain




# Python program to find order to process tasks
# so that all tasks can be finished. This program
# mainly uses Kahn's algorithm.
from collections import deque
 
# Returns adjacency list representation of graph from
# given set of pairs.
def make_graph(numTasks, prerequisites):
    graph = [set() for _ in range(numTasks)]
    for u, v in prerequisites:
        graph[v].add(u)
    return graph
 
# Computes in-degree of every vertex
def compute_indegree(graph):
    indegrees = [0] * len(graph)
    for neighbors in graph:
        for neigh in neighbors:
            indegrees[neigh] += 1
    return indegrees
 
# main function for topological sorting
def findOrder(numTasks, prerequisites):
    # Create an adjacency list
    graph = make_graph(numTasks, prerequisites)
     
    # Find vertices of zero degree
    indegrees = compute_indegree(graph)
    zeros = deque([i for i, degree in enumerate(indegrees) if degree == 0])
     
    # Find vertices in topological order
    # starting with vertices of 0 degree
    # and reducing degrees of adjacent.
    toposort = []
    while zeros:
        zero = zeros.popleft()
        toposort.append(zero)
        for neigh in graph[zero]:
            indegrees[neigh] -= 1
            if indegrees[neigh] == 0:
                zeros.append(neigh)
    return toposort if len(toposort) == numTasks else []
 
# Driver code
if __name__ == '__main__':
    numTasks = 4
    # for prerequisites: [[1, 0], [2, 1], [3, 2]]
    prerequisites = [(1, 0), (2, 1), (3, 2)]
    toposort = findOrder(numTasks, prerequisites)
    print(toposort)
 
# This code is contributed by Aman Kumar.




using System;
using System.Collections.Generic;
 
class Dep
{
   
  // Returns adjacency list representation of graph from
  // given set of pairs.
  static List<HashSet<int>> MakeGraph(int numTasks, int[][] prerequisites)
  {
    List<HashSet<int>> graph = new List<HashSet<int>>(numTasks);
    for (int i = 0; i < numTasks; i++)
      graph.Add(new HashSet<int>());
    foreach (int[] pre in prerequisites)
      graph[pre[1]].Add(pre[0]);
    return graph;
  }
 
  // Computes in-degree of every vertex
  static int[] ComputeIndegree(List<HashSet<int>> graph)
  {
    int[] degrees = new int[graph.Count];
    foreach (HashSet<int> neighbors in graph)
      foreach (int neigh in neighbors)
        degrees[neigh]++;
    return degrees;
  }
 
  // Main function for topological sorting
  static List<int> FindOrder(int numTasks, int[][] prerequisites)
  {
    // Create an adjacency list
    List<HashSet<int>> graph = MakeGraph(numTasks, prerequisites);
 
    // Find vertices of zero degree
    int[] degrees = ComputeIndegree(graph);
    Queue<int> zeros = new Queue<int>();
    for (int i = 0; i < numTasks; i++)
      if (degrees[i] == 0)
        zeros.Enqueue(i);
 
    // Find vertices in topological order
    // starting with vertices of 0 degree
    // and reducing degrees of adjacent.
    List<int> toposort = new List<int>();
    for (int i = 0; i < numTasks; i++)
    {
      if (zeros.Count == 0)
        return new List<int>();
      int zero = zeros.Peek();
      zeros.Dequeue();
      toposort.Add(zero);
      foreach (int neigh in graph[zero])
      {
        if (--degrees[neigh] == 0)
          zeros.Enqueue(neigh);
      }
    }
    return toposort;
  }
 
  // Driver code
  static void Main(string[] args)
  {
    int numTasks = 4;
    int[][] prerequisites = new int[][] { new int[] { 1, 0 }, new int[] { 2, 1 }, new int[] { 3, 2 } };
 
    List<int> v = FindOrder(numTasks, prerequisites);
 
    Console.WriteLine(string.Join(" ", v));
  }
}




// JavaScript program to find order to process tasks
// so that all tasks can be finished. This program
// mainly uses Kahn's algorithm.
 
// Returns adjacency list representation of graph from
// given set of pairs.
function make_graph(numTasks, prerequisites) {
let graph = new Array(numTasks).fill(null).map(() => new Set());
for (let i = 0; i < prerequisites.length; i++) {
let pre = prerequisites[i];
graph[pre[1]].add(pre[0]);
}
return graph;
}
 
// Computes in-degree of every vertex
function compute_indegree(graph) {
let degrees = new Array(graph.length).fill(0);
for (let neighbors of graph) {
for (let neigh of neighbors) {
degrees[neigh]++;
}
}
return degrees;
}
 
// main function for topological sorting
function findOrder(numTasks, prerequisites) {
// Create an adjacency list
let graph = make_graph(numTasks, prerequisites);
 
// Find vertices of zero degree
let degrees = compute_indegree(graph);
let zeros = [];
for (let i = 0; i < numTasks; i++) {
if (degrees[i] === 0) {
zeros.push(i);
}
}
 
// Find vertices in topological order
// starting with vertices of 0 degree
// and reducing degrees of adjacent.
let toposort = [];
for (let i = 0; i < numTasks; i++) {
if (zeros.length === 0) {
return [];
}
let zero = zeros.shift();
toposort.push(zero);
for (let neigh of graph[zero]) {
if (--degrees[neigh] === 0) {
zeros.push(neigh);
}
}
}
return toposort;
}
 
// Driver code
let numTasks = 4;
let prerequisites = [[1, 0], [2, 1], [3, 2]];
let v = findOrder(numTasks, prerequisites);
 
for (let i = 0; i < v.length; i++) {
console.log(v[i] + " ");
}
 
// This code is contributed by Pushpesh Raj.

Output
0 1 2 3 

Time complexity : O(N+E) where N is the number of tasks, and E is the number of prerequisite pairs.
Auxiliary Space:O(N+E)

Find the ordering of task from given dependencies using Topological Sorting using DFS:

The idea is to use a topological sort algorithm with depth-first search (DFS) to find a valid ordering of tasks given prerequisite pairs. Construct a directed graph where tasks are nodes and prerequisites are directed edges. Perform DFS to identify a valid order, ensuring there are no cycles in the graph. If a valid order exists, it’s returned; otherwise, an empty array is returned, indicating that it’s not possible to find a valid order.

Follow the steps to solve this problem:

Below is the implementation of above approach:




// CPP program to find Topological sorting using
// DFS
#include <bits/stdc++.h>
using namespace std;
   
// Returns adjacency list representation of graph from
// given set of pairs.
vector<vector<int> > make_graph(int numTasks,
             vector<pair<int, int> >& prerequisites)
{
    vector<vector<int> > graph(numTasks);
    for (auto pre : prerequisites)
        graph[pre.second].push_back(pre.first);
    return graph;
}
   
// Does DFS and adds nodes to Topological Sort
bool dfs(vector<vector<int> >& graph, int node, 
           vector<bool>& onpath, vector<bool>& visited, 
                                vector<int>& toposort)
{
    if (visited[node])
        return false;
    onpath[node] = visited[node] = true;
    for (int neigh : graph[node])
        if (onpath[neigh] || dfs(graph, neigh, onpath, visited, toposort))
            return true;
    toposort.push_back(node);
    return onpath[node] = false;
}
   
// Returns an order of tasks so that all tasks can be
// finished.
vector<int> findOrder(int numTasks, vector<pair<int, int> >& prerequisites)
{
    vector<vector<int> > graph = make_graph(numTasks, prerequisites);
    vector<int> toposort;
    vector<bool> onpath(numTasks, false), visited(numTasks, false);
    for (int i = 0; i < numTasks; i++)
        if (!visited[i] && dfs(graph, i, onpath, visited, toposort))
            return {};
    reverse(toposort.begin(), toposort.end());
    return toposort;
}
   
int main()
{
    int numTasks = 4;
    vector<pair<int, int> > prerequisites;
   
    // for prerequisites: [[1, 0], [2, 1], [3, 2]]
    prerequisites.push_back(make_pair(1, 0));
    prerequisites.push_back(make_pair(2, 1));
    prerequisites.push_back(make_pair(3, 2));
    vector<int> v = findOrder(numTasks, prerequisites);
   
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
   
    return 0;
}




// Java program to find Topological sorting using
// DFS
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
 
public class Dfs1 {
 
    // Returns adjacency list representation of graph from
    // given set of pairs.
    static ArrayList<HashSet<Integer> >
    make_graph(int numTasks, int[][] prerequisites)
    {
        ArrayList<HashSet<Integer> > graph
            = new ArrayList(numTasks);
        for (int i = 0; i < numTasks; i++)
            graph.add(new HashSet<Integer>());
        for (int[] pre : prerequisites)
            graph.get(pre[1]).add(pre[0]);
        return graph;
    }
 
    // Does DFS and adds nodes to Topological Sort
    static boolean dfs(ArrayList<HashSet<Integer> > graph,
                       int node, boolean[] onpath,
                       boolean[] visited,
                       ArrayList<Integer> toposort)
    {
        if (visited[node])
            return false;
        onpath[node] = visited[node] = true;
        for (int neigh : graph.get(node))
            if (onpath[neigh]
                || dfs(graph, neigh, onpath, visited,
                       toposort))
                return true;
        toposort.add(node);
        return onpath[node] = false;
    }
 
    // Returns an order of tasks so that all tasks can be
    // finished.
    static ArrayList<Integer>
    findOrder(int numTasks, int[][] prerequisites)
    {
        ArrayList<HashSet<Integer> > graph
            = make_graph(numTasks, prerequisites);
        ArrayList<Integer> toposort
            = new ArrayList<Integer>();
        boolean[] onpath = new boolean[numTasks];
        boolean[] visited = new boolean[numTasks];
        for (int i = 0; i < numTasks; i++)
            if (!visited[i]
                && dfs(graph, i, onpath, visited, toposort))
                return new ArrayList<Integer>();
        Collections.reverse(toposort);
        return toposort;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int numTasks = 4;
        int[][] prerequisites
            = { { 1, 0 }, { 2, 1 }, { 3, 2 } };
 
        ArrayList<Integer> v
            = findOrder(numTasks, prerequisites);
 
        for (int i = 0; i < v.size(); i++) {
            System.out.print(v.get(i) + " ");
        }
    }
}
 
// This code is contributed by Lovely Jain




#  Python program to find Topological sorting using
#  DFS
 
#  Returns adjacency list representation of graph from
#  given set of pairs.
def make_graph(numTasks, prerequisites):
    graph = {i: [] for i in range(numTasks)}
    for pre in prerequisites:
        graph[pre[1]].append(pre[0])
    return graph
 
 
#  Does DFS and adds nodes to Topological Sort
def dfs(graph, node, onpath, visited, toposort):
    if visited[node]:
        return False
    onpath[node] = visited[node] = True
    for neigh in graph[node]:
        if onpath[neigh] or dfs(graph, neigh, onpath, visited, toposort):
            return True
    toposort.append(node)
    return onpath[node] == False
 
 
#  Returns an order of tasks so that all tasks can be
#  finished.
def findOrder(numTasks, prerequisites):
    graph = make_graph(numTasks, prerequisites)
    toposort = []
    onpath = [False for i in range(numTasks)]
    visited = [False for i in range(numTasks)]
    for i in range(numTasks):
        if not visited[i] and dfs(graph, i, onpath, visited, toposort):
            return
    toposort = toposort[::-1]
    return toposort
 
# Driver code
if __name__ == "__main__":
    numTasks = 4
    prerequisites = [[1, 0], [2, 1], [3, 2]]
    v = findOrder(numTasks, prerequisites)
    for i in range(len(v)):
        print(v[i], end=" ")




// C# program to find Topological sorting using
// DFS
using System;
using System.Collections.Generic;
using System.Linq;
 
class Solution {
      // Returns adjacency list representation of graph from
    // given set of pairs.
    static List<HashSet<int>> MakeGraph(int numTasks, List<Tuple<int, int>> prerequisites) {
        var graph = new List<HashSet<int>>(numTasks);
 
        for (int i = 0; i < numTasks; i++) {
            graph.Add(new HashSet<int>());
        }
 
        foreach (var pre in prerequisites) {
            graph[pre.Item2].Add(pre.Item1);
        }
 
        return graph;
    }
    // Does DFS and adds nodes to Topological Sort
    static bool DFS(List<HashSet<int>> graph, int node, HashSet<int> onPath, HashSet<int> visited, List<int> topoSort) {
        if (visited.Contains(node)) {
            return false;
        }
 
        onPath.Add(node);
        visited.Add(node);
 
        foreach (var neigh in graph[node]) {
            if (onPath.Contains(neigh) || DFS(graph, neigh, onPath, visited, topoSort)) {
                return true;
            }
        }
 
        topoSort.Add(node);
        onPath.Remove(node);
 
        return false;
    }
    // Returns an order of tasks so that all tasks can be
    // finished.
    static List<int> FindOrder(int numTasks, List<Tuple<int, int>> prerequisites) {
        var graph = MakeGraph(numTasks, prerequisites);
        var topoSort = new List<int>();
        var onPath = new HashSet<int>();
        var visited = new HashSet<int>();
 
        for (int i = 0; i < numTasks; i++) {
            if (!visited.Contains(i) && DFS(graph, i, onPath, visited, topoSort)) {
                return new List<int>();
            }
        }
 
        topoSort.Reverse();
        return topoSort;
    }
 
    static void Main(string[] args) {
        int numTasks = 4;
          // for prerequisites: [[1, 0], [2, 1], [3, 2]]
        var prerequisites = new List<Tuple<int, int>> {
            Tuple.Create(1, 0),
            Tuple.Create(2, 1),
            Tuple.Create(3, 2)
        };
 
        var v = FindOrder(numTasks, prerequisites);
 
        foreach (var i in v) {
            Console.Write(i + " ");
        }
    }
}
 
// This code is contributed by Prince Kumar




// Returns adjacency list representation of graph from
// given set of pairs.
function makeGraph(numTasks, prerequisites) {
const graph = {};
for (let i = 0; i < numTasks; i++) {
graph[i] = [];
}
for (let i = 0; i < prerequisites.length; i++) {
const pre = prerequisites[i];
graph[pre[1]].push(pre[0]);
}
return graph;
}
 
// Does DFS and adds nodes to Topological Sort
function dfs(graph, node, onpath, visited, toposort) {
if (visited[node]) {
return false;
}
onpath[node] = visited[node] = true;
for (let i = 0; i < graph[node].length; i++) {
const neigh = graph[node][i];
if (onpath[neigh] || dfs(graph, neigh, onpath, visited, toposort)) {
return true;
}
}
toposort.push(node);
return onpath[node] === false;
}
 
// Returns an order of tasks so that all tasks can be
// finished.
function findOrder(numTasks, prerequisites) {
const graph = makeGraph(numTasks, prerequisites);
const toposort = [];
const onpath = new Array(numTasks).fill(false);
const visited = new Array(numTasks).fill(false);
for (let i = 0; i < numTasks; i++) {
if (!visited[i] && dfs(graph, i, onpath, visited, toposort)) {
return;
}
}
return toposort.reverse();
}
 
// Driver code
const numTasks = 4;
const prerequisites = [[1, 0], [2, 1], [3, 2]];
const v = findOrder(numTasks, prerequisites); temp="";
for (let i = 0; i < v.length; i++) {
temp = temp +v[i] + " ";
} console.log(temp);

Output
0 1 2 3 

Time complexity : O(N+E) where N is the number of tasks, and E is the number of prerequisite pairs.
Auxiliary Space:O(N+E)


Article Tags :