150NeetCode 150

88.Course Schedule II

MediumGraphs ยท 9/19

Problem

There are numCourses courses labelled 0 to numCourses - 1. Each pair prerequisites[i] = [a, b] means course b must be taken before course a.

Return an ordering of courses that lets you finish all of them. If several orderings are valid, return any of them. If it is impossible (the prerequisites contain a cycle), return an empty array.

Examples

Input:  numCourses = 2, prerequisites = [[1,0]]
Output: [0,1]
Explanation: Course 1 requires course 0, so 0 must come first.
Input:  numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3]
Explanation: 0 first; 1 and 2 each need only 0; 3 needs both 1 and 2. [0,2,1,3] is also accepted.
Input:  numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: []
Explanation: The two courses depend on each other, so no order exists.

Constraints

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)
  • prerequisites[i].length == 2
  • 0 <= a, b < numCourses, a != b
  • All pairs [a, b] are distinct

๐Ÿ’ก Key Insight

A valid course order is a topological order of the directed graph with edges b โ†’ a (prerequisite before course). It exists exactly when the graph is acyclic. Kahn's algorithm builds the order directly: repeatedly output a course with in-degree 0 and remove its outgoing edges. If fewer than numCourses courses are output, the leftovers form a cycle and the answer is []. Everything runs in O(V + E).

Brute Force (Repeated Elimination Rounds)

TimeO(Vยท(V + E))SpaceO(V)

Intuition

Plan semester by semester. In each round, scan every prerequisite pair to find which untaken courses are still blocked; every course that is not blocked can be taken now, so append it to the order. When a round adds nothing, stop. If the order contains every course, return it; otherwise there is a cycle.

Algorithm

  1. taken[] all false, order empty.
  2. Repeat:
    • blocked[a] = true for each [a, b] with b not taken.
    • Append every course that is neither taken nor blocked; mark it taken.
    • If no course was appended this round, stop.
  3. Return order if it has numCourses entries, else an empty array.

Visualization

numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]

round 1: blocked {1,2,3} โ†’ order = [0]
round 2: blocked {3}     โ†’ order = [0,1,2]
round 3: blocked {}      โ†’ order = [0,1,2,3]
round 4: nothing new     โ†’ stop, size 4 โ†’ return [0,1,2,3]

Code

java
class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        boolean[] taken = new boolean[numCourses];
        int[] order = new int[numCourses];
        int size = 0;

        while (true) {
            boolean[] blocked = new boolean[numCourses];
            for (int[] p : prerequisites) {
                if (!taken[p[1]]) blocked[p[0]] = true; // prerequisite still missing
            }
            boolean progress = false;
            for (int course = 0; course < numCourses; course++) {
                if (!taken[course] && !blocked[course]) {
                    taken[course] = true;
                    order[size++] = course;
                    progress = true;
                }
            }
            if (!progress) break;
        }
        return size == numCourses ? order : new int[0];
    }
}

Complexity

  • Time: O(Vยท(V + E)) โ€” up to V rounds, each scanning all pairs and all courses.
  • Space: O(V) โ€” taken, blocked and order.

Complexity Comparison

Approach Time Space
Repeated Elimination Rounds O(Vยท(V + E)) O(V)
DFS Post-Order O(V + E) O(V + E)
Kahn's Topological Sort O(V + E) O(V + E)

Common Pitfalls

  • Returning a partial order when a cycle exists โ€” the problem requires an empty array.
  • Mixing edge directions in DFS: with course โ†’ prerequisite edges the post-order is already correct; with prerequisite โ†’ course edges you must reverse the post-order.
  • Returning null instead of new int[0].
  • Forgetting courses that appear in no pair at all; they still have to be in the output (in-degree 0).
  • Detecting cycles with a plain visited flag, which wrongly rejects shared prerequisites (diamond shapes).