◀ THE GRIND — GRAPHS

Course Schedule II

MEDIUM✓ CHIP-TIMEDLC #210 — FULL STATEMENT ↗

The drill: Some courses require other courses first. Produce one valid order to take every course so no course comes before something it needs — or report that no such order exists because the requirements loop.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

Same setup as the yes/no version of this drill — a fixed number of courses and a list of prerequisite pairs — but this time the answer has to be an actual valid order to take every course, one where nothing appears before something it depends on.

Multiple valid orders can exist for the same input, and any one of them is acceptable — the grading only cares that every prerequisite pair is respected somewhere in the sequence produced.

When the requirements loop back on themselves and no valid order can exist at all, the expected answer is an empty list rather than a partial attempt.

EX 01
numCourses = 1 · prerequisites = []
[0]
ONE COURSE, NO REQUIREMENTS
EX 02
numCourses = 2 · prerequisites = [[1, 0]]
[0, 1]
ONE REQUIREMENT FORCES THE ORDER
EX 03
numCourses = 2 · prerequisites = [[1, 0], [0, 1]]
[]
THE TWO COURSES NEED EACH OTHER
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

This is the same requirement graph as before, but now the answer isn't yes/no — it's the actual order. Which courses are always safe to take right now, on any valid schedule?

HINT 2 THE STRUCTURE

A course is safe the moment every one of its prerequisites is already taken. That set of "safe now" courses changes as you take courses — the real question is how cheaply you can track it.

HINT 3 ONE STEP FROM THE ANSWER

Keep a running count of remaining prerequisites per course. Take any course sitting at zero, then decrement that count for everyone who depended on it — no rescanning needed, just a queue of newly-zeroed courses.

COACH'S BOARD — THE PATTERN, STEP BY STEP
THE PEEL ORDERPATTERN · TOPOLOGICAL SORT — KAHN5 courses · chain: 1→3→0→2→4
STEP 1

5 courses, numbered out of sequence: taking 1 unlocks 3, 3 unlocks 0, 0 unlocks 2, 2 unlocks 4. Count in-degrees first.

STEP 1 / 8 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/course-schedule-ii.pyRACE PACE
LANG ▸
PACE ▸
class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        graph = [[] for _ in range(numCourses)]
        indeg = [0] * numCourses
        for a, b in prerequisites:
            graph[b].append(a)  # taking b unlocks a
            indeg[a] += 1

        queue = collections.deque(c for c in range(numCourses) if indeg[c] == 0)
        order = []
        while queue:
            course = queue.popleft()
            order.append(course)
            for nxt in graph[course]:
                indeg[nxt] -= 1
                if indeg[nxt] == 0:
                    queue.append(nxt)

        return order if len(order) == numCourses else []
TIME O(V+E)SPACE O(V+E)PYTHON · RACE PACE · 19 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED