Skip to main content
  1. LeetCode/

LeetCode 207: Course Schedule

·2 mins· ·
LeetCode Medium Graph Topological-Sort
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: medium First Attempt: 2026-04-08 Source: Day 1 learning note

Study Context
#

This article is rebuilt from the exact LeetCode section in the learning note. I kept the note’s repair points, comparison points, and common mistakes, while removing unrelated non-LeetCode material from the same day.

Learning Note Extract
#

LC 207 - Course Schedule (Topological Sort / Cycle Detection)
#

  • Pattern: Topological Sort (Kahn’s BFS)
  • Key insight: If a valid topological ordering exists -> no cycle -> return true
  • Approach: Build adjacency list + in-degree array. Add all nodes with in-degree 0 to queue. Process queue; for each node, reduce each neighbor’s in-degree, and when it reaches 0, add it to queue. If the number of processed courses equals numCourses, there is no cycle.
  • Complexity: Time O(V + E), Space O(V + E)
  • Why deque over list: list.pop(0) is O(n) because it shifts all elements. deque.popleft() is O(1).

Organized Notes
#

This article should stay focused on the boolean cycle-detection version. LC 210 uses the same topological process but returns the order; LC 207 only needs to know whether every course can be processed. The two common repair points are edge direction (pre -> course) and not returning true until the processed count reaches numCourses.

Clean Solution
#

The note above captures the reasoning and the mistakes to avoid. The implementation below is the version I would submit.

from collections import deque
from typing import List

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        graph = [[] for _ in range(numCourses)]
        indeg = [0] * numCourses
        for course, pre in prerequisites:
            graph[pre].append(course)
            indeg[course] += 1

        q = deque(i for i in range(numCourses) if indeg[i] == 0)
        seen = 0
        while q:
            node = q.popleft()
            seen += 1
            for nei in graph[node]:
                indeg[nei] -= 1
                if indeg[nei] == 0:
                    q.append(nei)

        return seen == numCourses

Complexity
#

Time O(V+E), Space O(V+E).

Mistakes To Watch
#

  • Reversing edge direction inconsistently.
  • Returning true before checking all nodes.

Final Interview Explanation
#

I would build edges from prerequisite to course and count how many courses Kahn’s algorithm can process. If a cycle exists, the queue eventually empties before all courses are processed. So seen == numCourses is the proof that all prerequisites can be satisfied.

Related

LeetCode 210: Course Schedule II
·2 mins
LeetCode Medium Graph Topological-Sort
LeetCode note for Course Schedule II, rebuilt from the original learning note
LeetCode 2192: All Ancestors of a Node in a DAG
·3 mins
LeetCode Medium Graph Topological-Sort
LeetCode note for All Ancestors of a Node in a DAG, rebuilt from the original learning note
LeetCode 1971: Find if Path Exists in Graph
·2 mins
LeetCode Easy Graph Union-Find
LeetCode note for Find if Path Exists in Graph, rebuilt from the original learning note
LeetCode 1497: Check If Array Pairs Are Divisible by k (Remainder Pairing, Modulo)
·2 mins
LeetCode Daily Medium Array Hash-Map Complement Counting Math Modulo
Remainder pairing with a hash map; handle 0 and k/2 remainders carefully.
LeetCode 1695: Maximum Erasure Value (Sliding Window)
·1 min
LeetCode Daily Medium Array Sliding-Window Two-Pointers Hash-Set
Sliding window with a set and running sum; two pointers to keep the subarray unique.
LeetCode 209: Minimum Size Subarray Sum (Sliding Window)
·1 min
LeetCode Daily Medium Array Sliding-Window Two-Pointers Prefix-Sum Binary-Search
Sliding window with two pointers; minimize subarray length where sum ≥ target.