AlgoMaster Logo

Parallel Courses

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

We have n courses with prerequisite relationships forming a directed graph. Each semester, we can take all courses whose prerequisites have been completed. We want the minimum number of semesters to finish everything, or -1 if a cycle makes it impossible.

This is a graph problem. The courses are nodes, and the prerequisites are directed edges. Taking "any number of courses as long as prerequisites are met" means we can take all courses with zero remaining prerequisites in a single semester. That maps to processing all nodes with in-degree 0 at each step, which is what BFS-based topological sorting does, level by level.

The minimum number of semesters equals the length of the longest prerequisite chain in the graph. Courses with no prerequisites go in semester 1. Courses that depend only on semester-1 courses go in semester 2, and so on. Each BFS level corresponds to one semester. If a cycle exists, the courses on it can never be scheduled, so the answer is -1.

Key Constraints:

  • 1 <= n <= 5000 and 1 <= relations.length <= 5000 → At most 5,000 nodes and 5,000 edges. The graph is sparse, so an adjacency list with O(n + E) traversal is the natural representation.
  • prevCoursei != nextCoursei → No self-loops, but cycles involving multiple nodes are still possible, which is why cycle detection is required to return -1.

Approach 1: BFS Topological Sort (Kahn's Algorithm)

Intuition

We can simulate the semester process directly. In each semester, we take every course whose prerequisites are already completed. In semester 1, that is the courses with no prerequisites at all, meaning their in-degree (number of incoming edges) is 0.

After finishing semester 1, we remove those courses from the graph. Some courses now have all their prerequisites satisfied, giving them in-degree 0, and those go into semester 2. We repeat until either all courses are taken or no course has in-degree 0 (a cycle means the courses on it never reach in-degree 0).

This is Kahn's algorithm for topological sorting. Instead of producing a single linear order, we process all zero-in-degree nodes together as one level (one semester) and count how many levels we need.

Algorithm

  1. Build an adjacency list from the relations and compute the in-degree of each course.
  2. Add all courses with in-degree 0 to a queue. These are our semester-1 courses.
  3. Initialize a semester counter to 0 and a counter for courses taken.
  4. While the queue is not empty:
    • Increment the semester counter.
    • Process all courses currently in the queue (this is one semester).
    • For each course, decrement the in-degree of all its neighbors. If any neighbor's in-degree becomes 0, add it to the queue.
    • Add the number of courses processed to the total courses taken.
  5. If courses taken equals n, return the semester count. Otherwise, return -1 (cycle detected).

Visualization and Code

Loading animation...

The next approach reaches the same answer from a different angle. Instead of simulating semesters one level at a time, it computes the longest prerequisite chain in the graph directly with DFS.

Approach 2: DFS with Longest Path

Intuition

The minimum number of semesters equals the longest chain of prerequisites. If course A requires B, which requires C, which requires D, that is a chain of length 4, so we need at least 4 semesters no matter what else is in the graph.

The problem reduces to finding the longest path in a directed graph. For each node, we compute the longest path starting from it, and the answer is the maximum over all nodes.

DFS with memoization computes this efficiently. The longest path from a course is 1 (the course itself) plus the maximum longest path among the courses it is a prerequisite for. Caching each result avoids recomputing shared sub-chains.

Cycle detection rides along on the same traversal. If DFS reaches a node that is still being explored on the current path, the graph has a cycle. A three-state marking handles this: unvisited (0), visiting (on the DFS stack, marked -1), and visited (fully processed, a positive depth value).

Algorithm

  1. Build an adjacency list from the relations.
  2. Create an array maxDepth to store the longest path from each node (initialized to 0, meaning unvisited).
  3. For each course from 1 to n, if it hasn't been visited, run DFS on it.
  4. In the DFS function:
    • Mark the node as "visiting" (set maxDepth to -1 as a sentinel).
    • For each neighbor, if it's "visiting" (maxDepth == -1), we found a cycle, return -1. If it's unvisited, recurse.
    • The node's depth is 1 + max depth among all neighbors (or 1 if no neighbors).
    • Mark the node as "visited" by storing its computed depth.
  5. Return the maximum value in maxDepth. If any DFS returned -1, the whole answer is -1.

Visualization and Code

Loading animation...