Course Schedule IV
Course Schedule IV is LeetCode 1462 (Medium). There are numCourses courses labelled 0 to numCourses - 1, and a list prerequisites where each pair [a, b] means course a must be taken before course b.
- Prerequisites chain: if
acomes beforebandbbeforec, thenais a prerequisite ofctoo, even though no pair says so. - Each query
[u, v]asks whetheruis a prerequisite ofv, directly or through a chain. Return one boolean per query. - The graph has no cycles,
numCourses ≤ 100and there are up to 10⁴ queries, so answers should be precomputed rather than searched per query.
- 2 <= numCourses <= 100
- 0 <= prerequisites.length <= (numCourses * (numCourses - 1) / 2)
- prerequisites[i].length == 2
- 0 <= ai, bi <= numCourses - 1
- ai != bi
- All the pairs [ai, bi] are unique.
- The prerequisites graph has no cycles.
- 1 <= queries.length <= 10⁴
- 0 <= ui, vi <= numCourses - 1
- ui != vi
Intuition
Each query in the course schedule iv LeetCode problem asks whether a chain of arrows leads from u to v. Searching the graph once per query repeats the same work up to 10⁴ times. Instead, compute once, for every course v, the set required[v] of all courses that must come before it. That all-pairs reachability is the transitive closure, and afterwards each query is one lookup.
The sets build on each other: for an arrow u → v, everything required before u, plus u itself, is required before v. That copy is only safe once required[u] is complete, and topological order guarantees exactly that.
Many is X reachable from Y questions against one fixed graph mean precompute reachability once. On a DAG, a node's answer is built from its predecessors' answers, so topological order is the natural fill order. On a small graph (n ≤ 100) a Floyd-Warshall boolean matrix does the same job in three nested loops.
Approach
Before reading on, decide what to store per course so that any query is one lookup, and in what order the courses must be processed so that nothing is copied before it is complete. Aim for O(n·E + Q) time.
Two ways to solve it
Process courses in topological order and push each course's prerequisite set to the courses it unlocks.
- Fast on sparse input: work follows the edges, not n³.
- Order-safe: a set is complete before it is copied.
- More code: in-degrees, a queue and a set per course.
The better choice when there are few prerequisites.
Fill a boolean matrix reach, then let every course k in turn act as a middle step between pairs.
- Short: three nested loops and no queue.
- Fixed cost: about 10⁶ steps at n = 100.
- Watch out:
kmust be the outermost loop.
Fine here because n is tiny.
Both build the full transitive closure, but Kahn's work grows with the number of prerequisites while Floyd-Warshall always pays n³. The steps, code and live demo below follow Kahn's algorithm; the Floyd-Warshall code comes after the demo.
Build the graph in the right direction
For each pair [a, b], add the arrow a → b and raise b's in-degree. Here the first course of a pair comes first, the opposite of Course Schedule I and II, so copying their edge code silently reverses every answer.
Seed the queue
Put every course with in-degree 0 in the queue. Nothing comes before them, so their required sets are empty and already final, which makes them safe to copy from.
Pop a course and push its set forward
For each arrow course → nxt:
- merge
required[course]intorequired[nxt]; - add
courseitself torequired[nxt]; - lower
nxt's in-degree, and queue it when that reaches 0.
A course is popped only after every arrow into it was handled, so its set is complete before anything copies it.
Answer each query with one lookup
Query [u, v] is true exactly when u is in required[v]. The set belongs to the later course and lists what must come before it, so the lookup is O(1).
Course Schedule IV solution in Python | C++ | Java
[a, b] says a must be taken before b, so draw the arrow a → b. Note the order: this is the reverse of Course Schedule I and II, where [a, b] means b comes first. The goal is to fill required[v], every course that must come before v, directly or through a chain. Then each query is one lookup.required[0] = {} is complete and safe to copy along its 2 outgoing arrows.required[1] = {0} can no longer grow. Only now is it safe for 1 to pass its set on, so it joins the queue.required[2] = {0} can no longer grow. Only now is it safe for 2 to pass its set on, so it joins the queue.required[1] = {0} is complete and safe to copy along its 1 outgoing arrow.required[2] = {0} is complete and safe to copy along its 1 outgoing arrow.required[3] = {0, 1, 2} can no longer grow. Only now is it safe for 3 to pass its set on, so it joins the queue.required[3] = {0, 1, 2} is complete and safe to copy along its 1 outgoing arrow.required[4] = {0, 1, 2, 3} can no longer grow. Only now is it safe for 4 to pass its set on, so it joins the queue.[a, b] says a must be taken before b, so draw the arrow a → b. Note the order: this is the reverse of Course Schedule I and II, where [a, b] means b comes first. The goal is to fill required[v], every course that must come before v, directly or through a chain. Then each query is one lookup.required[1] = {} is complete and safe to copy along its 1 outgoing arrow.required[0] = {1} can no longer grow. Only now is it safe for 0 to pass its set on, so it joins the queue.[a, b] says a must be taken before b, so draw the arrow a → b. Note the order: this is the reverse of Course Schedule I and II, where [a, b] means b comes first. The goal is to fill required[v], every course that must come before v, directly or through a chain. Then each query is one lookup.required[1] = {} is complete and safe to copy along its 2 outgoing arrows.required[2] = {1} can no longer grow. Only now is it safe for 2 to pass its set on, so it joins the queue.required[2] = {1} is complete and safe to copy along its 1 outgoing arrow.required[0] = {1, 2} can no longer grow. Only now is it safe for 0 to pass its set on, so it joins the queue.Floyd-Warshall (boolean matrix)
Start with reach[a][b] = True for each pair. For every middle course k, any i that reaches k also reaches everything k reaches; after all k, reach[u][v] answers each query.
Common pitfalls
Checking only direct prerequisites
return [v in graph[u] for u, v in queries]
return [u in required[v] for u, v in queries]
A prerequisite can be indirect. With pairs [0,1] and [1,2], course 0 must come before 2 although no pair says so; the adjacency list answers false.
Merging in input order instead of topological order
for a, b in prerequisites:
required[b] |= required[a] | {a}# pop courses from a Kahn queue, so required[a] # is complete before it is copied
Pairs can arrive in any order. With [[1,2],[0,1]], the first line copies required[1] into 2 while it is still empty; 0 reaches 1 only afterwards, so [0, 2] wrongly answers false.
Copying the ancestors but not the course itself
required[nxt] |= required[course]
required[nxt] |= required[course] required[nxt].add(course)
The course at the tail of the arrow is the most direct prerequisite of all. A course with no prerequisites of its own has an empty set, so without the add nothing ever reaches its dependants and every answer is false.
Complexity
Course Schedule I, II and IV side by side
The three share a name and a graph but ask different questions, and IV even reads its pairs the other way round.
| Problem | Pair [a, b] means | Question | Method |
|---|---|---|---|
| Course Schedule (207) | b before a | Can every course be finished? | Kahn's algorithm or DFS cycle check |
| Course Schedule II (210) | b before a | Give one valid order | Kahn's algorithm, return the pop order |
| Course Schedule IV (1462) | a before b | Is u a prerequisite of v, directly or not? | Transitive closure: Kahn with sets, or Floyd-Warshall |
Course Schedule IV FAQ
How do you solve Course Schedule IV on LeetCode?
- Graph: arrow
a → bfor each pair[a, b], and in-degrees. - Order: Kahn's algorithm, starting from courses with in-degree 0.
- Sets: for each arrow
course → nxt, mergerequired[course]andcourseintorequired[nxt]. - Queries:
[u, v]isu in required[v]. - Cost: O(n·E) to build, O(1) per query.
What is the transitive closure in Course Schedule IV?
It is the full comes-before relation: u is related to v whenever a chain of prerequisite arrows leads from u to v. Storing it as one set per course (or an n × n boolean matrix) turns every query into a lookup.
Why does the course schedule iv solution need topological order?
A course's set is copied into the courses that depend on it. If it is copied before all of its own prerequisites have arrived, the copy is incomplete and chains get cut. Kahn's algorithm only pops a course after every arrow into it has been processed, so each set is final when it is copied.