Compilation Order
curriculum-track — return a valid build order for projects given their dependencies via topological sort.
Medium
Time
O(V + E) Space O(V + E) 4 min read
topological-sort graph
Problem#
(curriculum variant.) Given projects (string names) and dependency pairs [a, b] meaning “a must be built before b”, return any valid build order. Return [] if impossible.
Examples#
projects = ["a","b","c","d","e","f"], deps = [["a","d"],["f","b"],["b","d"],["f","a"],["d","c"]]→["e","f","a","b","d","c"]
Approach#
Standard Kahn’s BFS over the dependency DAG.
Solution#
vector<string> compilationOrder(vector<string> projects, vector<pair<string,string>> deps) { unordered_map<string, vector<string>> adj; unordered_map<string, int> indeg; for (auto& p : projects) indeg[p]; for (auto& [a, b] : deps) { adj[a].push_back(b); ++indeg[b]; } queue<string> q; for (auto& p : projects) if (indeg[p] == 0) q.push(p); vector<string> out; while (!q.empty()) { string u = q.front(); q.pop(); out.push_back(u); for (auto& v : adj[u]) if (--indeg[v] == 0) q.push(v); } return (int)out.size() == (int)projects.size() ? out : vector<string>{};}func compilationOrder(projects []string, deps [][2]string) []string { adj := map[string][]string{} indeg := map[string]int{} for _, p := range projects { indeg[p] = 0 } for _, d := range deps { a, b := d[0], d[1] adj[a] = append(adj[a], b) indeg[b]++ } queue := []string{} for _, p := range projects { if indeg[p] == 0 { queue = append(queue, p) } } out := []string{} for len(queue) > 0 { u := queue[0] queue = queue[1:] out = append(out, u) for _, v := range adj[u] { indeg[v]-- if indeg[v] == 0 { queue = append(queue, v) } } } if len(out) == len(projects) { return out } return []string{}}from typing import List, Tuplefrom collections import defaultdict, deque
class Solution: def compilationOrder(self, projects: List[str], deps: List[Tuple[str, str]]) -> List[str]: adj: dict = defaultdict(list) indeg: dict = {p: 0 for p in projects} for a, b in deps: adj[a].append(b) indeg[b] += 1 queue = deque(p for p in projects if indeg[p] == 0) out: List[str] = [] while queue: u = queue.popleft() out.append(u) for v in adj[u]: indeg[v] -= 1 if indeg[v] == 0: queue.append(v) return out if len(out) == len(projects) else []function compilationOrder(projects, deps) { const adj = new Map(); const indeg = new Map(); for (const p of projects) indeg.set(p, 0); for (const [a, b] of deps) { if (!adj.has(a)) adj.set(a, []); adj.get(a).push(b); indeg.set(b, (indeg.get(b) ?? 0) + 1); } const queue = []; for (const p of projects) if (indeg.get(p) === 0) queue.push(p); const out = []; while (queue.length) { const u = queue.shift(); out.push(u); for (const v of adj.get(u) ?? []) { indeg.set(v, indeg.get(v) - 1); if (indeg.get(v) === 0) queue.push(v); } } return out.length === projects.length ? out : [];}class Solution { public List<String> compilationOrder(List<String> projects, List<String[]> deps) { Map<String, List<String>> adj = new HashMap<>(); Map<String, Integer> indeg = new HashMap<>(); for (String p : projects) indeg.put(p, 0); for (String[] d : deps) { String a = d[0], b = d[1]; adj.computeIfAbsent(a, k -> new ArrayList<>()).add(b); indeg.put(b, indeg.getOrDefault(b, 0) + 1); } Deque<String> queue = new ArrayDeque<>(); for (String p : projects) if (indeg.get(p) == 0) queue.offer(p); List<String> out = new ArrayList<>(); while (!queue.isEmpty()) { String u = queue.poll(); out.add(u); for (String v : adj.getOrDefault(u, Collections.emptyList())) { indeg.put(v, indeg.get(v) - 1); if (indeg.get(v) == 0) queue.offer(v); } } return out.size() == projects.size() ? out : new ArrayList<>(); }}function compilationOrder(projects: string[], deps: [string, string][]): string[] { const adj = new Map<string, string[]>(); const indeg = new Map<string, number>(); for (const p of projects) indeg.set(p, 0); for (const [a, b] of deps) { if (!adj.has(a)) adj.set(a, []); adj.get(a)!.push(b); indeg.set(b, (indeg.get(b) ?? 0) + 1); } const queue: string[] = []; for (const p of projects) if (indeg.get(p) === 0) queue.push(p); const out: string[] = []; while (queue.length) { const u = queue.shift()!; out.push(u); for (const v of adj.get(u) ?? []) { indeg.set(v, indeg.get(v)! - 1); if (indeg.get(v) === 0) queue.push(v); } } return out.length === projects.length ? out : [];}Editorial#
Same Kahn’s BFS as Course Schedule II. Build dependency DAG, enumerate zero-indegree, process and decrement.
Complexity#
- Time: O(V + E).
- Space: O(V + E).
Concept revision#
Related#