210. Course Schedule II
Problem Statement
There are a total of numCourses
courses you have to
take, labeled from 0
to numCourses-1
. Some
courses may have prerequisites, given as a list
prerequisites
where prerequisites[i] = [a, b]
indicates that you must take course b
before course
a
.
Return the ordering of courses you should take to finish all courses. If there are multiple valid answers, return any of them. If it is impossible to finish all courses, return an empty array.
My Solution
To solve this problem, I used Topological Sort. Here's the step-by-step approach I took:
- Graph Representation: Represent the courses and their prerequisites as a graph using an adjacency list.
- Indegree Array: Keep track of how many prerequisites each course has.
- Queue for Zero Indegree: Process courses with zero prerequisites first and update the indegree of their dependent courses accordingly.
- Cycle Detection: Check if all courses have been processed to detect cycles.
What is Topological Sort?
Topological Sort is a linear ordering of vertices in a directed graph
such that for every directed edge u -> v
, vertex
u
comes before v
in the ordering. This is
particularly useful in scenarios like scheduling tasks, course
prerequisites, or any situation where certain tasks must precede
others.
Key Concepts:
- Directed Acyclic Graph (DAG): A graph with directed edges and no cycles. Topological sort only works on DAGs.
- Dependencies (Edges): If task
A
must be done before taskB
, there is a directed edge fromA
toB
. - Indegree: The number of incoming edges to a node.
Nodes with zero indegree can be processed immediately as they have no
dependencies.
1
2
3
4
5
6
7
8
9
10
11
12
13# Example: [[1, 0], [2, 0], [3, 1], [3, 2]]
# Graph:
0 -> 1: Course 0 is a prerequisite for Course 1.
0 -> 2: Course 0 is a prerequisite for Course 2.
1 -> 3: Course 1 is a prerequisite for Course 3.
2 -> 3: Course 2 is a prerequisite for Course 3.
# Indegree of a course = Number of prerequisites.
indegree[0] = 0 (No prerequisites)
indegree[1] = 1 (Prerequisite: Course 0)
indegree[2] = 1 (Prerequisite: Course 0)
indegree[3] = 2 (Prerequisites: Courses 1, 2)
Steps to Perform Topological Sort:
- Graph Representation: Represent the tasks and dependencies using an adjacency list.
- Indegree Calculation: For each task, count the number of dependencies it has (indegree).
- Queue Initialisation: Start with tasks that have no dependencies (indegree of zero).
- Process Tasks: Repeatedly take tasks with zero indegree from the queue, add them to the result, and decrease the indegree of their dependent tasks. Add newly dependency-free tasks to the queue.
- Check for Cycles: If all tasks are processed, a valid ordering exists. If not, there's a cycle, and a valid ordering is impossible.
Applying Topological Sort to Course Schedule II:
To solve the Course Schedule II problem using topological sort, follow these steps:
- Graph Representation: Use an adjacency list to represent courses and their prerequisites.
- Indegree Array: Track the number of prerequisites (indegree) for each course.
- Queue for Zero Indegree: Use a queue to manage courses with zero prerequisites.
- Topological Sort:
- Process nodes with zero indegree.
- Add the course to the result list.
- Reduce the indegree for all its neighbors.
- Add neighbors with zero indegree to the queue.
- Cycle Detection: If the number of processed courses
is less than
numCourses
, there is a cycle, and you should return an empty array.
Example Workflow:
Consider numCourses = 4
and
prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]]
:
- Graph and Indegree Construction:
adj = [[1, 2], [3], [3], []]
indegree = [0, 1, 1, 2]
- Initialise Queue:
- Courses with zero indegree:
[0]
- Courses with zero indegree:
- Process Courses:
- Process
0
:result = [0]
- Decrease indegree of
1
and2
:indegree = [0, 0, 0, 2]
- Add
1
and2
to queue:queue = [1, 2]
- Decrease indegree of
- Process
1
:result = [0, 1]
- Decrease indegree of
3
:indegree = [0, 0, 0, 1]
- Decrease indegree of
- Process
2
:result = [0, 1, 2]
- Decrease indegree of
3
:indegree = [0, 0, 0, 0]
- Add
3
to queue:queue = [3]
- Decrease indegree of
- Process
3
:result = [0, 1, 2, 3]
- Process
- Check for Cycles:
result.length === numCourses
:[0, 1, 2, 3]
Code Implementation
1 | /** |
Summary:
Topological sort is a powerful algorithm for ordering tasks with dependencies. Recognise it by looking for prerequisite relationships and apply it by ensuring tasks are processed only when their dependencies are met.