Compute build order from dependencies
Company: Uber
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of graph algorithms and dependency resolution, specifically topological ordering and cycle detection, within the Coding & Algorithms domain and tests both conceptual understanding and practical application of graph traversal and ordering techniques.
Constraints
- 0 <= n <= 10^4
- 0 <= dependencies.length <= 10^5
- Each dependency is a pair [a, b] with 0 <= a, b < n and a != b
- Duplicate dependency pairs may appear and count as one edge
- Among packages that are simultaneously ready, build the smallest-label one first
- Return [] if and only if the dependency graph contains a cycle
Examples
Input: (4, [[1, 0], [2, 0], [3, 1], [3, 2]])
Expected Output: [0, 1, 2, 3]
Explanation: 0 builds first (no deps); then 1 and 2 (both depend only on 0, smaller label 1 first); finally 3 (depends on 1 and 2).
Input: (2, [[1, 0], [0, 1]])
Expected Output: []
Explanation: 0 depends on 1 and 1 depends on 0 — a 2-node cycle, so no valid build order exists.
Hints
- Model packages as nodes and each dependency [a, b] as a directed edge b -> a (b must come before a). The build order is a topological sort of this graph.
- Use Kahn's algorithm: repeatedly take a node with in-degree 0, append it to the order, and decrement the in-degree of its successors. Deduplicate edges first so duplicate pairs don't inflate in-degrees.
- For the deterministic 'smallest label first' rule, replace the plain queue with a min-heap of ready nodes. If at the end you have placed fewer than n nodes, some nodes were stuck in a cycle — return an empty list.
- The alternative DFS post-order approach pushes a node onto a stack after visiting all its dependencies, then reverses the stack; it detects cycles via a recursion/'in-progress' marker. Kahn's is often preferred here because in-degree tracking makes the smallest-label tie-break and cycle reporting straightforward without deep recursion.