Course Schedule II
Return a valid course order — Kahn's BFS topological sort.
3 min read
topological-sort graph
Problem#
Given numCourses and prerequisites [course, prereq], return any valid course-taking order, or [] if impossible.
Examples#
numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]→[0,2,1,3](or similar)
Constraints#
1 <= numCourses <= 2000.
Approach#
Same Kahn’s BFS as Course Schedule, but accumulate the output order.
Solution#
class Solution {public: vector<int> findOrder(int n, vector<vector<int>>& prerequisites) { vector<vector<int>> adj(n); vector<int> indeg(n, 0); for (auto& p : prerequisites) { adj[p[1]].push_back(p[0]); ++indeg[p[0]]; } queue<int> q; for (int i = 0; i < n; ++i) if (indeg[i] == 0) q.push(i); vector<int> out; while (!q.empty()) { int u = q.front(); q.pop(); out.push_back(u); for (int v : adj[u]) if (--indeg[v] == 0) q.push(v); } return (int)out.size() == n ? out : vector<int>{}; }};func findOrder(n int, prerequisites [][]int) []int { adj := make([][]int, n) indeg := make([]int, n) for _, p := range prerequisites { adj[p[1]] = append(adj[p[1]], p[0]) indeg[p[0]]++ } q := []int{} for i := 0; i < n; i++ { if indeg[i] == 0 { q = append(q, i) } } out := []int{} for len(q) > 0 { u := q[0] q = q[1:] out = append(out, u) for _, v := range adj[u] { indeg[v]-- if indeg[v] == 0 { q = append(q, v) } } } if len(out) == n { return out } return []int{}}from typing import Listfrom collections import deque
class Solution: def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: adj = [[] for _ in range(numCourses)] indeg = [0] * numCourses for course, prereq in prerequisites: adj[prereq].append(course) indeg[course] += 1 q = deque(i for i in range(numCourses) if indeg[i] == 0) out = [] while q: u = q.popleft() out.append(u) for v in adj[u]: indeg[v] -= 1 if indeg[v] == 0: q.append(v) return out if len(out) == numCourses else []function findOrder(numCourses, prerequisites) { const adj = Array.from({ length: numCourses }, () => []); const indeg = new Array(numCourses).fill(0); for (const [course, prereq] of prerequisites) { adj[prereq].push(course); indeg[course]++; } const q = []; for (let i = 0; i < numCourses; i++) if (indeg[i] === 0) q.push(i); const out = []; while (q.length) { const u = q.shift(); out.push(u); for (const v of adj[u]) if (--indeg[v] === 0) q.push(v); } return out.length === numCourses ? out : [];}class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { List<List<Integer>> adj = new ArrayList<>(); for (int i = 0; i < numCourses; i++) adj.add(new ArrayList<>()); int[] indeg = new int[numCourses]; for (int[] p : prerequisites) { adj.get(p[1]).add(p[0]); indeg[p[0]]++; } Deque<Integer> q = new ArrayDeque<>(); for (int i = 0; i < numCourses; i++) if (indeg[i] == 0) q.offer(i); int[] out = new int[numCourses]; int idx = 0; while (!q.isEmpty()) { int u = q.poll(); out[idx++] = u; for (int v : adj.get(u)) { if (--indeg[v] == 0) q.offer(v); } } return idx == numCourses ? out : new int[0]; }}function findOrder(numCourses: number, prerequisites: number[][]): number[] { const adj: number[][] = Array.from({ length: numCourses }, () => []); const indeg: number[] = new Array(numCourses).fill(0); for (const [course, prereq] of prerequisites) { adj[prereq].push(course); indeg[course]++; } const q: number[] = []; for (let i = 0; i < numCourses; i++) if (indeg[i] === 0) q.push(i); const out: number[] = []; let head = 0; while (head < q.length) { const u = q[head++]; out.push(u); for (const v of adj[u]) if (--indeg[v] === 0) q.push(v); } return out.length === numCourses ? out : [];}Editorial#
Cycle detection by mismatched output length. Output order may vary based on tie-breaking.
Complexity#
- Time: O(V + E).
- Space: O(V + E).
Concept revision#
Related#