Earliest Completion Time of Jobs

Last Updated : 24 Jul, 2026

Given a Directed Acyclic Graph (DAG) with V jobs (numbered from 1 to V) and E dependency edges[][], where each edge [u, v] indicates that job v can start only after job u has been completed, find the earliest completion time of every job. Each job takes exactly one unit of time to complete, and any number of independent jobs can be executed simultaneously. Return an array of size V, where the elements represent the earliest completion times of jobs 1 to V in order.

Examples:

Input: V = 10, E = 13, edges[][] = [[1, 3], [1, 4], [1, 5], [2, 4], [2, 8], [2, 9], [3, 6], [4, 6], [4, 8], [5, 8], [6, 7], [7, 8], [8, 10]]
Output: [1, 1, 2, 2, 2, 3, 4, 5, 2, 6]
Explanation:
Jobs 1 and 2 have no prerequisites, so they complete at time 1.
Jobs 3, 4, 5, and 9 can start only after their prerequisites are completed, so they complete at time 2.
Job 6 depends on jobs 3 and 4, so it completes at time 3.
Job 7 depends on job 6, so it completes at time 4.
Job 8 depends on jobs 2, 4, 5, and 7. Since job 7 finishes last (at time 4), job 8 completes at time 5.
Job 10 depends on job 8, so it completes at time 6.

blobid0_1782986746


Input: V = 7, E = 7, edges[][] = [[1, 2], [2, 3], [2, 4], [2, 5], [3, 6], [4, 6], [5, 7]]
Output: [1, 2, 3, 3, 3, 4, 4]
Explanation:
Job 1 has no prerequisite, so it completes at time 1.
Job 2 depends on job 1, so it completes at time 2.
Jobs 3, 4, and 5 depend on job 2, so they complete at time 3.
Job 6 depends on jobs 3 and 4, so it completes at time 4.
Job 7 depends on job 5, so it also completes at time 4.

blobid1_1782986763
Try It Yourself
redirect icon

[Naive Approach] Using DFS from Every Job - O(V × (V + E)) Time and O(V + E) Space

The idea is to build a reverse graph (u->v is stored as v->u). Once we build reverse graph, it becomes easy to perform a DFS for every job to find the maximum completion time among all its prerequisite jobs..The completion time of a job is 1 + the maximum completion time of its prerequisites. Since DFS is repeated for every job, many computations are performed multiple times.

Working of the Approach:

  • First, construct a reverse graph where for every dependency u → v, an edge v → u is stored. This allows us to directly access all prerequisite jobs of any job.
  • For each job, perform a DFS on the reverse graph. If a job has no prerequisites, it can start immediately, so its completion time is 1.
  • While traversing the prerequisites, recursively compute their earliest completion times and keep track of the maximum among them, since the current job must wait for all its prerequisites to finish.
  • Finally, assign the current job's completion time as 1 + maximum completion time of its prerequisites. Repeating this for every job gives the earliest completion time of all jobs.
C++
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

// Returns the earliest completion time of the current job.
int dfs(int node, vector<vector<int>> &revGraph)
{
    // No prerequisite jobs.
    if (revGraph[node].empty())
        return 1;

    int mxTime = 0;

    // Find the maximum completion time among all prerequisites.
    for (int prev : revGraph[node])
        mxTime = max(mxTime, dfs(prev, revGraph));

    return mxTime + 1;
}

vector<int> minTime(int V, vector<vector<int>> &edges)
{
    // Build the reverse graph.
    vector<vector<int>> revGraph(V);

    for (auto &edge : edges)
    {
        int u = edge[0] - 1;
        int v = edge[1] - 1;

        revGraph[v].push_back(u);
    }

    // Stores the earliest completion time of every job.
    vector<int> ans(V);

    // Compute the completion time for every job.
    for (int i = 0; i < V; i++)
        ans[i] = dfs(i, revGraph);

    return ans;
}

int main()
{
    int V = 10;

    vector<vector<int>> edges = {{1, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 8}, {2, 9}, {3, 6},
                                 {4, 6}, {4, 8}, {5, 8}, {6, 7}, {7, 8}, {8, 10}};

    vector<int> ans = minTime(V, edges);

    cout << "[";

    for (int i = 0; i < ans.size(); i++)
    {
        cout << ans[i];

        if (i != ans.size() - 1)
            cout << ", ";
    }

    cout << "]";

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

public class GFG {

    // Returns the earliest completion time of the current
    // job.
    static int dfs(int node,
                   ArrayList<ArrayList<Integer> > revGraph)
    {

        // No prerequisite jobs.
        if (revGraph.get(node).isEmpty())
            return 1;

        int mxTime = 0;

        // Find the maximum completion time among all
        // prerequisites.
        for (int prev : revGraph.get(node))
            mxTime = Math.max(mxTime, dfs(prev, revGraph));

        return mxTime + 1;
    }

    static ArrayList<Integer> minTime(int V, int[][] edges)
    {

        // Build the reverse graph.
        ArrayList<ArrayList<Integer> > revGraph
            = new ArrayList<>();

        for (int i = 0; i < V; i++)
            revGraph.add(new ArrayList<>());

        for (int[] edge : edges) {
            int u = edge[0] - 1;
            int v = edge[1] - 1;

            revGraph.get(v).add(u);
        }

        // Stores the earliest completion time of every job.
        ArrayList<Integer> ans = new ArrayList<>();

        // Compute the completion time for every job.
        for (int i = 0; i < V; i++)
            ans.add(dfs(i, revGraph));

        return ans;
    }

    public static void main(String[] args)
    {

        int V = 10;

        int[][] edges
            = { { 1, 3 }, { 1, 4 }, { 1, 5 }, { 2, 4 },
                { 2, 8 }, { 2, 9 }, { 3, 6 }, { 4, 6 },
                { 4, 8 }, { 5, 8 }, { 6, 7 }, { 7, 8 },
                { 8, 10 } };

        ArrayList<Integer> ans = minTime(V, edges);

        System.out.print("[");

        for (int i = 0; i < ans.size(); i++) {
            System.out.print(ans.get(i));

            if (i != ans.size() - 1)
                System.out.print(", ");
        }

        System.out.print("]");
    }
}
Python
# Returns the earliest completion time of the current job.
def dfs(node, revGraph):
    # No prerequisite jobs.
    if not revGraph[node]:
        return 1

    mxTime = 0

    # Find the maximum completion time among all prerequisites.
    for prev in revGraph[node]:
        mxTime = max(mxTime, dfs(prev, revGraph))

    return mxTime + 1


def minimumTime(V, edges):
    # Build the reverse graph.
    revGraph = [[] for _ in range(V)]

    for u, v in edges:
        revGraph[v - 1].append(u - 1)

    # Stores the earliest completion time of every job.
    ans = []

    # Compute the completion time for every job.
    for i in range(V):
        ans.append(dfs(i, revGraph))

    return ans


if __name__ == "__main__":
    V = 10

    edges = [
        [1, 3], [1, 4], [1, 5], [2, 4], [2, 8],
        [2, 9], [3, 6], [4, 6], [4, 8], [5, 8],
        [6, 7], [7, 8], [8, 10]
    ]

    ans = minimumTime(V, edges)

    print(ans)
C#
using System;
using System.Collections.Generic;

class GFG {
    // Returns the earliest completion time of the current
    // job.
    static int Dfs(int node, List<List<int> > revGraph)
    {
        // No prerequisite jobs.
        if (revGraph[node].Count == 0)
            return 1;

        int mxTime = 0;

        // Find the maximum completion time among all
        // prerequisites.
        foreach(int prev in revGraph[node]) mxTime
            = Math.Max(mxTime, Dfs(prev, revGraph));

        return mxTime + 1;
    }

    static List<int> minTime(int V, int[, ] edges)
    {
        // Build the reverse graph.
        List<List<int> > revGraph = new List<List<int> >();

        for (int i = 0; i < V; i++)
            revGraph.Add(new List<int>());

        int E = edges.GetLength(0);

        for (int i = 0; i < E; i++) {
            int u = edges[i, 0] - 1;
            int v = edges[i, 1] - 1;

            revGraph[v].Add(u);
        }

        // Stores the earliest completion time of every job.
        List<int> ans = new List<int>();

        // Compute the completion time for every job.
        for (int i = 0; i < V; i++)
            ans.Add(Dfs(i, revGraph));

        return ans;
    }

    static void Main()
    {
        int V = 10;

        int[, ] edges
            = { { 1, 3 }, { 1, 4 }, { 1, 5 }, { 2, 4 },
                { 2, 8 }, { 2, 9 }, { 3, 6 }, { 4, 6 },
                { 4, 8 }, { 5, 8 }, { 6, 7 }, { 7, 8 },
                { 8, 10 } };

        List<int> ans = minTime(V, edges);

        Console.Write("[");

        for (int i = 0; i < ans.Count; i++) {
            Console.Write(ans[i]);

            if (i != ans.Count - 1)
                Console.Write(", ");
        }

        Console.Write("]");
    }
}
JavaScript
function dfs(node, revGraph)
{
    // No prerequisite jobs.
    if (revGraph[node].length === 0)
        return 1;

    let mxTime = 0;

    // Find the maximum completion time among all
    // prerequisites.
    for (let prev of revGraph[node])
        mxTime = Math.max(mxTime, dfs(prev, revGraph));

    return mxTime + 1;
}

function minTime(V, edges)
{
    // Build the reverse graph.
    let revGraph = Array.from({length : V}, () => []);

    for (let edge of edges) {
        let u = edge[0] - 1;
        let v = edge[1] - 1;

        revGraph[v].push(u);
    }

    // Stores the earliest completion time of every job.
    let ans = Array(V).fill(0);

    // Compute the completion time for every job.
    for (let i = 0; i < V; i++)
        ans[i] = dfs(i, revGraph);

    return ans;
}

// Driver Code
let V = 10;

let edges = [
    [ 1, 3 ], [ 1, 4 ], [ 1, 5 ], [ 2, 4 ], [ 2, 8 ],
    [ 2, 9 ], [ 3, 6 ], [ 4, 6 ], [ 4, 8 ], [ 5, 8 ],
    [ 6, 7 ], [ 7, 8 ], [ 8, 10 ]
];

let ans = minTime(V, edges);

console.log("[");

for (let i = 0; i < ans.length; i++) {
    process.stdout.write(ans[i].toString());

    if (i !== ans.length - 1)
        process.stdout.write(", ");
}

console.log("]");

Output
[1, 1, 2, 2, 2, 3, 4, 5, 2, 6]

[Expected Approach] Using Topological Sorting (Kahn's Algorithm) - O(V + E) Time and O(V + E) Space

The idea is to process the jobs in topological order using Kahn's Algorithm. Jobs with no prerequisites are assigned a completion time of 1. As each job is processed, its dependent jobs are updated, and once all prerequisites of a job are completed, its completion time is assigned as current job's completion time + 1. This processes every job and edge only once.

Let us understand with an example:
Input: V = 10, E = 13, edges[][] = [[1, 3], [1, 4], [1, 5], [2, 4], [2, 8], [2, 9], [3, 6], [4, 6], [4, 8], [5, 8], [6, 7], [7, 8], [8, 10]]

  • Build the graph and compute the indegree of every job. Jobs 1 and 2 have indegree 0, so they are added to the queue and assigned completion time 1.
  • Process jobs 1 and 2 first. After all their prerequisites are satisfied, jobs 3, 4, 5, and 9 become ready and are assigned completion time 2.
  • Next, process jobs 3 and 4. Once both are completed, job 6 has no remaining prerequisites and gets completion time 3.
  • Processing job 6 makes job 7 ready with completion time 4. After processing job 7, job 8 becomes ready and gets completion time 5.
  • Finally, processing job 8 makes job 10 ready, so its completion time becomes 6. The final answer is [1, 1, 2, 2, 2, 3, 4, 5, 2, 6].
C++
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

// Compute the earliest completion time of every job.
void findTime(int V, vector<int> graph[], vector<int> &time, vector<int> &indegree)
{

    queue<int> q;

    // Jobs with no dependencies finish at time 1.
    for (int i = 0; i < V; i++)
    {
        if (indegree[i] == 0)
        {
            q.push(i);
            time[i] = 1;
        }
    }

    // Process jobs in topological order.
    while (!q.empty())
    {
        int curr = q.front();
        q.pop();

        // Visit all dependent jobs.
        for (int next : graph[curr])
        {
            indegree[next]--;

            // All prerequisites of this job are completed.
            if (indegree[next] == 0)
            {
                time[next] = time[curr] + 1;
                q.push(next);
            }
        }
    }
}

vector<int> minTime(int V, vector<vector<int>> &edges)
{

    // Build the graph and compute indegrees.
    vector<int> graph[V], indegree(V, 0);

    for (auto &edge : edges)
    {
        int u = edge[0] - 1;
        int v = edge[1] - 1;

        graph[u].push_back(v);
        indegree[v]++;
    }

    // Stores the earliest completion time of each job.
    vector<int> time(V);

    findTime(V, graph, time, indegree);

    return time;
}

int main()
{
    int V = 10;

    vector<vector<int>> edges = {{1, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 8}, {2, 9}, {3, 6},
                                 {4, 6}, {4, 8}, {5, 8}, {6, 7}, {7, 8}, {8, 10}};

    vector<int> ans = minTime(V, edges);

    cout << "[";

    for (int i = 0; i < ans.size(); i++)
    {
        cout << ans[i];

        if (i != ans.size() - 1)
            cout << ", ";
    }

    cout << "]";

    return 0;
}
Java
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class GFG {

    // Compute the earliest completion time of every job.
    static void
    findTime(int V, ArrayList<ArrayList<Integer> > graph,
             int[] time, int[] indegree)
    {

        Queue<Integer> q = new LinkedList<>();

        // Jobs with no dependencies finish at time 1.
        for (int i = 0; i < V; i++) {
            if (indegree[i] == 0) {
                q.offer(i);
                time[i] = 1;
            }
        }

        // Process jobs in topological order.
        while (!q.isEmpty()) {
            int curr = q.poll();

            // Visit all dependent jobs.
            for (int next : graph.get(curr)) {
                indegree[next]--;

                // All prerequisites of this job are
                // completed.
                if (indegree[next] == 0) {
                    time[next] = time[curr] + 1;
                    q.offer(next);
                }
            }
        }
    }

    static ArrayList<Integer> minTime(int V, int[][] edges)
    {

        // Build the graph and compute indegrees.
        ArrayList<ArrayList<Integer> > graph
            = new ArrayList<>();

        for (int i = 0; i < V; i++)
            graph.add(new ArrayList<>());

        int[] indegree = new int[V];

        for (int[] edge : edges) {
            int u = edge[0] - 1;
            int v = edge[1] - 1;

            graph.get(u).add(v);
            indegree[v]++;
        }

        // Stores the earliest completion time of each job.
        int[] time = new int[V];

        findTime(V, graph, time, indegree);

        ArrayList<Integer> ans = new ArrayList<>();
        for (int x : time)
            ans.add(x);

        return ans;
    }

    public static void main(String[] args)
    {
        int V = 10;

        int[][] edges
            = { { 1, 3 }, { 1, 4 }, { 1, 5 }, { 2, 4 },
                { 2, 8 }, { 2, 9 }, { 3, 6 }, { 4, 6 },
                { 4, 8 }, { 5, 8 }, { 6, 7 }, { 7, 8 },
                { 8, 10 } };

        ArrayList<Integer> ans = minTime(V, edges);

        System.out.print("[");

        for (int i = 0; i < ans.size(); i++) {
            System.out.print(ans.get(i));

            if (i != ans.size() - 1)
                System.out.print(", ");
        }

        System.out.print("]");
    }
}
Python
from collections import deque

# Compute the earliest completion time of every job.


def findTime(V, graph, time, indegree):

    q = deque()

    # Jobs with no dependencies finish at time 1.
    for i in range(V):
        if indegree[i] == 0:
            q.append(i)
            time[i] = 1

    # Process jobs in topological order.
    while q:
        curr = q.popleft()

        # Visit all dependent jobs.
        for next in graph[curr]:
            indegree[next] -= 1

            # All prerequisites of this job are completed.
            if indegree[next] == 0:
                time[next] = time[curr] + 1
                q.append(next)


def minTime(V, edges):

    # Build the graph and compute indegrees.
    graph = [[] for _ in range(V)]
    indegree = [0] * V

    for edge in edges:
        u = edge[0] - 1
        v = edge[1] - 1

        graph[u].append(v)
        indegree[v] += 1

    # Stores the earliest completion time of each job.
    time = [0] * V

    findTime(V, graph, time, indegree)

    return time


if __name__ == "__main__":
    V = 10

    edges = [[1, 3], [1, 4], [1, 5], [2, 4], [2, 8], [2, 9], [3, 6],
             [4, 6], [4, 8], [5, 8], [6, 7], [7, 8], [8, 10]]

    ans = minTime(V, edges)

    print('[')

    for i in range(len(ans)):
        print(ans[i], end='')

        if i != len(ans) - 1:
            print(', ', end='')

    print(']')
C#
using System;
using System.Collections.Generic;

class GFG {
    // Compute the earliest completion time of every job.
    static void FindTime(int V, List<int>[] graph,
                         int[] time, int[] indegree)
    {
        Queue<int> q = new Queue<int>();

        // Jobs with no dependencies finish at time 1.
        for (int i = 0; i < V; i++) {
            if (indegree[i] == 0) {
                q.Enqueue(i);
                time[i] = 1;
            }
        }

        // Process jobs in topological order.
        while (q.Count > 0) {
            int curr = q.Dequeue();

            // Visit all dependent jobs.
            foreach(int next in graph[curr])
            {
                indegree[next]--;

                // All prerequisites of this job are
                // completed.
                if (indegree[next] == 0) {
                    time[next] = time[curr] + 1;
                    q.Enqueue(next);
                }
            }
        }
    }

    static List<int> minTime(int V, int[, ] edges)
    {
        // Build the graph and compute indegrees.
        List<int>[] graph = new List<int>[ V ];
        for (int i = 0; i < V; i++)
            graph[i] = new List<int>();

        int[] indegree = new int[V];

        int m = edges.GetLength(0);

        for (int i = 0; i < m; i++) {
            int u = edges[i, 0] - 1;
            int v = edges[i, 1] - 1;

            graph[u].Add(v);
            indegree[v]++;
        }

        // Stores the earliest completion time of each job.
        int[] time = new int[V];

        FindTime(V, graph, time, indegree);

        return new List<int>(time);
    }

    static void Main()
    {
        int V = 10;

        int[, ] edges
            = { { 1, 3 }, { 1, 4 }, { 1, 5 }, { 2, 4 },
                { 2, 8 }, { 2, 9 }, { 3, 6 }, { 4, 6 },
                { 4, 8 }, { 5, 8 }, { 6, 7 }, { 7, 8 },
                { 8, 10 } };

        List<int> ans = minTime(V, edges);

        Console.Write("[");

        for (int i = 0; i < ans.Count; i++) {
            Console.Write(ans[i]);

            if (i != ans.Count - 1)
                Console.Write(", ");
        }

        Console.Write("]");
    }
}
JavaScript
// Compute the earliest completion time of every job.
function findTime(V, graph, time, indegree)
{

    let q = [];

    // Jobs with no dependencies finish at time 1.
    for (let i = 0; i < V; i++) {
        if (indegree[i] === 0) {
            q.push(i);
            time[i] = 1;
        }
    }

    // Process jobs in topological order.
    while (q.length > 0) {
        let curr = q.shift();

        // Visit all dependent jobs.
        for (let next of graph[curr]) {
            indegree[next]--;

            // All prerequisites of this job are completed.
            if (indegree[next] === 0) {
                time[next] = time[curr] + 1;
                q.push(next);
            }
        }
    }
}

function minTime(V, edges)
{

    // Build the graph and compute indegrees.
    let graph = Array.from({length : V}, () => []);
    let indegree = Array(V).fill(0);

    for (let edge of edges) {
        let u = edge[0] - 1;
        let v = edge[1] - 1;

        graph[u].push(v);
        indegree[v]++;
    }

    // Stores the earliest completion time of each job.
    let time = Array(V).fill(0);

    findTime(V, graph, time, indegree);

    return time;
}

// Driver Code
let V = 10;

let edges = [
    [ 1, 3 ], [ 1, 4 ], [ 1, 5 ], [ 2, 4 ], [ 2, 8 ],
    [ 2, 9 ], [ 3, 6 ], [ 4, 6 ], [ 4, 8 ], [ 5, 8 ],
    [ 6, 7 ], [ 7, 8 ], [ 8, 10 ]
];

let ans = minTime(V, edges);

console.log("[");

for (let i = 0; i < ans.length; i++) {
    console.log(ans[i]);

    if (i !== ans.length - 1) {
        process.stdout.write(", ");
    }
}

console.log("]");

Output
[1, 1, 2, 2, 2, 3, 4, 5, 2, 6]
Comment