Katkat

Find a Valid Task Execution Order with Dependencies

SalesforceSoftware Engineer · Onsite

Last updated

Tests the ability to model workflow dependencies as a directed graph, perform topological sorting, and detect cycles.

Problem Statement

You are building a task execution engine for a cloud workflow system. You are given an integer numTasks representing the total number of tasks to execute, labeled from 0 to numTasks - 1.

You are also given a 2D array prerequisites, where prerequisites[i] = [task_a, task_b] indicates that task_b must be completed before task_a can be started (i.e., task_b -> task_a).

Return a valid sequence of tasks that allows all tasks to be completed. If there are multiple valid execution orders, return any one of them. If it is impossible to finish all tasks due to cyclic dependencies, return an empty array [].

Function Signature

def findTaskOrder(numTasks: int, prerequisites: list[list[int]]) -> list[int]:
    pass

Examples

Example 1

Input: numTasks = 2, prerequisites = [[1, 0]]
Output: [0, 1]
Explanation: To run task 1, task 0 must be finished first. Therefore, the only valid order is [0, 1].

Example 2

Input: numTasks = 4, prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]]
Output: [0, 1, 2, 3]
Explanation: Task 0 must be run before tasks 1 and 2. Task 3 requires both tasks 1 and 2 to finish. Another valid order is [0, 2, 1, 3].

Example 3

Input: numTasks = 2, prerequisites = [[1, 0], [0, 1]]
Output: []
Explanation: Task 1 depends on task 0, and task 0 depends on task 1. This circular dependency makes it impossible to complete all tasks.

Constraints

  • 1 <= numTasks <= 2000
  • 0 <= len(prerequisites) <= 5000
  • prerequisites[i].length == 2
  • 0 <= task_a, task_b < numTasks
  • task_a != task_b
  • All prerequisite pairs [task_a, task_b] are distinct.

Edge Cases

  • prerequisites is empty: any permutation of [0, ..., numTasks - 1] is valid.
  • Disconnected components: tasks with no dependencies can appear anywhere as long as relative dependencies are satisfied.
  • Graphs containing self-contained sub-cycles: the entire process should return [].

Hints

Hint 1

Model the tasks as nodes and dependencies as directed edges where an edge points from a prerequisite task to the dependent task.

Hint 2

Track the in-degree of each node; tasks with an in-degree of 0 have no outstanding dependencies and can be executed immediately.

Hint 3

If using BFS (Kahn's algorithm), append completed nodes to the result list and decrement neighbors' in-degrees; if the final list length is less than numTasks, a cycle exists.

Follow-up questions

  • How would you modify your algorithm to return the lexicographically smallest execution order if multiple valid orders exist?
  • If independent tasks can be executed in parallel and each task takes 1 unit of time, how would you determine the minimum total time required to complete all tasks?
  • How would you adapt this solution if the graph is too large to fit in memory on a single machine?