Learn how to tackle Course Schedule II, a key topic for Adobe SDE 2 interviews. This blog covers graph theory, topological sorting, and provides a Python implementation.
Blog
Hey there! I'm Shishir, a Director of Technology at Target and a former Technical Lead at Adobe. In this article, we’ll discuss a coding problem that's been asked at Adobe SDE 2 interviews.
This problem is about figuring out the order in which you should take a series of courses, given their prerequisites.
It's a classic example of using graph theory and topological sorting in computer science.
Let's dive in and explore how we can tackle this problem step by step.
There are a total of numCourses
courses you have to take, labeled from 0
to numCourses - 1
.
You are given an array prerequisites
where prerequisites[i] = [ai, bi]
indicates that you must take course bi
first if you want to take course ai
.
Return the ordering of courses you should take to finish all courses. If there are many valid answers, return any of them. If it is impossible to finish all courses, return an empty array.
Example 1
Input: numCourses = 2, prerequisites = [[1,0]]
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1].
Example 2
Input: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output: [0,2,1,3]
Explanation: There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0.
So one correct course order is [0,1,2,3]. Another correct ordering is [0,2,1,3].
Example 3
Input: numCourses = 1, prerequisites = []
Output: [0]
Constraints:
To solve the "Course Schedule II" problem, we can use a graph-based approach, specifically Topological Sorting.
The idea is to represent the courses and their prerequisites as a directed graph, where each vertex represents a course, and each edge (a, b)
represents that course b
is a prerequisite for course a
.
The goal is to find a topological order of the courses, which is an ordering of the vertices in a directed graph such that for every directed edge (a, b)
, vertex a
comes before b
in the ordering.
A course schedule is possible if and only if the graph has no cycles.
We can detect cycles and find a topological order using Depth-First Search (DFS) or by using Kahn's algorithm (a BFS approach). Here, I'll demonstrate the solution using DFS:
def findOrder(numCourses, prerequisites):
# Create a graph using an adjacency list representation
graph = [[] for _ in range(numCourses)]
for course, prereq in prerequisites:
graph[course].append(prereq)
# States: 0 = unvisited, 1 = visiting, 2 = visited
visit = [0] * numCourses
order = []
def dfs(course):
if visit[course] == 1: # Cycle detected
return False
if visit[course] == 2: # Already visited
return True
visit[course] = 1 # Mark as visiting
for prereq in graph[course]:
if not dfs(prereq):
return False
visit[course] = 2 # Mark as visited
order.append(course) # Add to topological order
return True
# Try to visit each course
for course in range(numCourses):
if not dfs(course):
return [] # Cycle detected, return empty list
return order
# Example usage
numCourses = 4
prerequisites = [[1,0],[2,0],[3,1],[3,2]]
print(findOrder(numCourses, prerequisites))
📌 Graph Representation: We first convert the list of prerequisites into a graph represented as an adjacency list. Each course points to its prerequisites.
📌 DFS and Cycle Detection: We use DFS to traverse the graph. For each course, we mark it as visiting
(state 1).
If we encounter a course that is already in the visiting
state during DFS, it means we've detected a cycle, and it's impossible to complete all courses.
If a course is in the visited
state (state 2), it means we've already processed it, and we can skip it.
📌 Topological Order: During the DFS, once we finish visiting all prerequisites for a course, we mark it as visited
(state 2) and add it to the topological order.
This ensures that a course is added to the order only after all its prerequisites are added.
📌 Detecting Impossible Schedules: If a cycle is detected at any point (meaning it's impossible to take all courses due to circular dependencies), we immediately return an empty list.
📌 Returning the Order: If no cycles are detected, we return the topological order of courses, which represents a valid sequence in which all courses can be completed.
This approach ensures that we correctly handle all prerequisites and detect any impossible course schedules due to circular dependencies.
********************
I hope you found this breakdown of the Course Schedule II question helpful. If you're preparing for Adobe interviews or just want to practice more problems like this, I'd be happy to help.
Feel free to book a free trial session with me.
I'm always excited to connect with fellow engineers and share what I've learned. Don't hesitate to get in touch, and good luck with your coding journey!
Copyright ©2024 Preplaced.in
Preplaced Education Private Limited
Ibblur Village, Bangalore - 560103
GSTIN- 29AAKCP9555E1ZV