Read-only web browser

Solutions

Browse the interview solutions folder with syntax highlighting.

course-schedule-ii.py

graphs/course-schedule-ii.py · Python · 2.9 KiB · 2026-04-10 08:12

Back to folder
# Topological sort (Kahn's algorithm) or DFS. Direction of edges changes depending on algorithm.
# graphs


# Topological sort (Kahn's algorithm) - O(V+E) time, O(V+E) space
def findOrder1(numCourses: int, prerequisites: list[list[int]]) -> list[int]:
    # NB: we need prereq -> [courses] for Kahn's (for DFS we need course -> [prereqs])
    adj = {i: [] for i in range(numCourses)} # {i: [courses i is a prereq of]}
    indregree = [0] * numCourses
    for a,b in prerequisites:
        adj[b].append(a) # a is prereq of b
        indregree[a] += 1

    from collections import deque
    q = deque()

    for c in range(numCourses):
        if indregree[c] == 0:
            q.append(c)

    out = []
    while q:
        c = q.popleft()
        out.append(c)

        for nei in adj[c]:
            indregree[nei] -= 1
            if indregree[nei] == 0:
                q.append(nei)
    
    if any(i > 0 for i in indregree):
        return []
    else:
        return out


# DFS - O(V+E) time, O(V+E) space
def findOrder(numCourses: int, prerequisites: list[list[int]]) -> list[int]:
    prereq = {i: [] for i in range(numCourses)} 
    # NB: in DFS we need course -> prereqs, whereas in Kahn's we need prereq -> courses.
    for crs, pre in prerequisites:
        prereq[crs].append(pre)  # pre is a prereq of crs

    out = []

    def dfs(c: int, cycle: set[int], visited: set[int]) -> bool:
        if c in cycle:
            return False
        if c in visited:
            return True
        
        cycle.add(c)
        for pre in prereq[c]:
            if not dfs(pre, cycle, visit):
                return False
        cycle.remove(c)
        visit.add(c)
        out.append(c)
        return True

    # NB: we need both a cycle set and a visited set,
    # because we want to be able to detect cycles even if we've already visited some nodes.
    visit = set()
    # NB: iterate over all courses, not just the ones in prereq,
    # because there may be courses with no prereqs that we still need to add to the output.
    for crs in range(numCourses):
        if not dfs(crs, set(), visit):
            return []
    return out
    
# Topological sort (DFS) - O(V+E) time, O(V+E) space
def findOrder(numCourses: int, prerequisites: list[list[int]]) -> list[int]:
    # NB: we need prereq -> [courses] for Kahn's (for DFS we need course -> [prereqs])
    adj = {i: [] for i in range(numCourses)}
    indegree = [0] * numCourses
    for nxt, pre in prerequisites:
        indegree[nxt] += 1
        adj[pre].append(nxt) # all courses that have pre as a prereq

    output = []

    def dfs(node: int):
        output.append(node)
        indegree[node] -= 1
        for nei in adj[node]:
            indegree[nei] -= 1
            if indegree[nei] == 0:
                dfs(nei)

    for i in range(numCourses):
        if indegree[i] == 0:
            dfs(i)

    return output if len(output) == numCourses else []