Learnitweb

Problem 210: Course Schedule II

You are given the number of courses and a list of prerequisite pairs.
Your task is to find an ordering in which you can finish all courses.

This is a classic directed graph problem where each course is a node, and each prerequisite is a directed edge.

If a valid ordering exists, return it.
If it is impossible due to cycles, return an empty array.


Understanding the Problem

Example:

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

Meaning:
To take course 1, you must complete 0
To take course 2, you must complete 0
To take course 3, you must complete 1 and 2

One valid order is: [0, 1, 2, 3]

If there is a cycle (like 0 depends on 1 and 1 depends on 0), no valid ordering exists.


Approach (Explained in Simple Language)

The best solution uses Topological Sorting using Kahn’s Algorithm.

Here is the concept in very simple terms:

1. Represent courses as a directed graph

Each course is a node.
Each prerequisite pair [a, b] means b → a (b must come before a).

2. Count indegree of each node

Indegree means how many prerequisites a course has.
Example: indegree[a] = number of courses required before a.

3. Start with all courses that have indegree 0

These have no prerequisites and can be taken immediately.

Put all such courses into a queue.

4. Process the queue

Repeatedly remove a course from the queue and add it to the result ordering.
Then reduce the indegree of its dependent courses.

If reducing indegree makes some course reach 0, add it to the queue.

5. If all courses are processed, the ordering is valid

Otherwise, if there are unprocessed courses with indegree > 0, a cycle exists.
In that case, return an empty array.


Java Code

import java.util.*;

public class CourseScheduleII {

    public int[] findOrder(int numCourses, int[][] prerequisites) {

        List<List<Integer>> graph = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) {
            graph.add(new ArrayList<>());
        }

        int[] indegree = new int[numCourses];

        for (int[] pre : prerequisites) {
            int course = pre[0];
            int prereq = pre[1];
            graph.get(prereq).add(course);
            indegree[course]++;
        }

        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (indegree[i] == 0) {
                queue.offer(i);
            }
        }

        int[] result = new int[numCourses];
        int index = 0;

        while (!queue.isEmpty()) {
            int current = queue.poll();
            result[index++] = current;

            for (int next : graph.get(current)) {
                indegree[next]--;
                if (indegree[next] == 0) {
                    queue.offer(next);
                }
            }
        }

        if (index == numCourses) {
            return result;
        }

        return new int[0];
    }

    public static void main(String[] args) {
        CourseScheduleII solution = new CourseScheduleII();
        int[][] prerequisites = {{1,0},{2,0},{3,1},{3,2}};
        int[] result = solution.findOrder(4, prerequisites);
        System.out.println(Arrays.toString(result));
    }
}

Dry Run

Input:

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

Meaning:
0 → 1
0 → 2
1 → 3
2 → 3

We want the order such that prerequisites appear first.


Step 1: Build graph and indegree array

Graph representation:
0 → [1, 2]
1 → [3]
2 → [3]
3 → []

Indegree:
0 = 0
1 = 1
2 = 1
3 = 2

Explanation:
1 depends on 0
2 depends on 0
3 depends on 1 and 2


Step 2: Add all courses with indegree 0 to queue

Queue = [0]
Only course 0 has no prerequisites.


Step 3: Process queue

Remove 0

Order = [0]

Reduce indegree of 1 and 2:
indegree[1] becomes 0
indegree[2] becomes 0

Add both to queue:

Queue = [1, 2]


Remove 1

Order = [0, 1]

Reduce indegree of 3:
indegree[3] becomes 1

Queue = [2]


Remove 2

Order = [0, 1, 2]

Reduce indegree of 3:
indegree[3] becomes 0

Add 3 to queue:

Queue = [3]


Remove 3

Order = [0, 1, 2, 3]

No further neighbors.


Step 4: Check if we processed all courses

index = 4 which is equal to numCourses = 4
So ordering is valid.

Output = [0, 1, 2, 3]


Why This Approach Works

Topological sorting is designed for problems where one task must come before another.
By repeatedly removing nodes with zero indegree, we ensure that all prerequisites of every course come before it in the final ordering.

If a cycle exists, no node will reach indegree 0, and we know no valid course ordering is possible.