Order Tasks with Dependencies Using a Deterministic Topological Sort
OpenAISoftware Engineer · Technical ScreenLast updated
Tests deterministic topological sorting of a directed acyclic graph using Kahn's algorithm and a priority queue to guarantee lexicographical tie-breaking.
Problem Statement
You are building a build system that must execute a set of tasks according to their prerequisites. You are given a list of unique task names tasks and a list of directed dependencies dependencies, where each dependency is a pair [prereq, task], indicating that prereq must be executed before task.
Return a list of all task names in a valid execution order such that:
- Every task appears exactly once.
- For every dependency
[prereq, task],prereqappears beforetaskin the output. - Whenever multiple tasks are simultaneously ready to run, the task with the lexicographically smallest name is chosen first.
- Disconnected tasks (tasks with no incoming or outgoing dependencies) are also included in the schedule according to the same rules.
If the dependency graph contains a cycle and no valid topological order is possible, return an empty list [].
Function Signature
def order_tasks(tasks: list[str], dependencies: list[list[str]]) -> list[str]:
pass
Examples
Example 1
Input:
tasks = ["build", "test", "lint", "deploy"]
dependencies = [["lint", "test"], ["build", "test"], ["test", "deploy"]]
Output: ["build", "lint", "test", "deploy"]
Explanation:
- Initially, both "build" and "lint" have 0 unmet prerequisites.
- Lexicographically, "build" comes before "lint", so "build" is executed first.
- Next, "lint" is executed.
- Now, "test" has all prerequisites satisfied and executes.
- Finally, "deploy" executes.
Example 2
Input:
tasks = ["zeta", "alpha", "beta"]
dependencies = []
Output: ["alpha", "beta", "zeta"]
Explanation: No dependencies exist, so tasks are scheduled in lexicographical order.
Constraints
1 <= len(tasks) <= 20,0000 <= len(dependencies) <= 50,000- Each task name consists of 1 to 20 lowercase English letters.
- All names in
tasksare unique. - In each dependency
[u, v], bothuandvare guaranteed to belong totasksandu != v. - Dependencies may contain duplicate pairs.
Hints
Hint 1
Track the in-degree (number of unmet prerequisites) for each task and construct an adjacency list.
Hint 2
When multiple tasks have an in-degree of 0, Kahn's algorithm selects the next task to process; what data structure lets you always pick the lexicographically smallest available task?
Hint 3
Use a min-heap initialized with all tasks of in-degree 0; whenever a task completes and decrements a neighbor's in-degree to 0, push that neighbor into the heap.
Follow-up questions
- How would you modify the solution to output tasks grouped by parallel execution stages (e.g., all tasks that can be run concurrently in round 1, round 2, etc.)?
- If a cycle is detected, how would you return the exact list of tasks involved in the cycle rather than just an empty list?
- How does your algorithm handle scaling if there are millions of tasks and dependencies that do not fit in memory on a single machine?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.