Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Graph Algorithms
MediumLC 210

Course Schedule II (LeetCode 210)

Target Frequency:MetaAmazonGoogleApple

You have numCourses courses to complete, numbered 0 through numCourses - 1, and a list prerequisites where each entry [ai, bi] means course bi must be completed before course ai.

  • So an entry [0, 1] means course 1 has to be finished before course 0.

Produce one valid order in which all courses can be taken; any correct order is acceptable. If no order can complete every course, return an empty list instead.

Worked Examples

Example 1
Input:numCourses = 2, prerequisites = [[1,0]]
Output:[0,1]
Explanation: Course 1 depends on course 0, so 0 must come first, giving the order [0, 1].
Example 2
Input:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output:[0,2,1,3]
Explanation: Course 3 depends on both 1 and 2, and each of those depends on course 0. Any order that places 0 first and 3 last works, e.g. [0, 1, 2, 3] or [0, 2, 1, 3].
Example 3
Input:numCourses = 1, prerequisites = []
Output:[0]
Explanation: There is one course with no prerequisites, so the order is just [0].

⚖️Formal Constraints & Bounds

  • 1 <= numCourses <= 2000

  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)

  • prerequisites[i].length == 2

  • 0 <= ai, bi < numCourses

  • ai != bi

  • All the pairs [ai, bi] are distinct

Deep-Dive & Conceptual Insights

Core Insight

Kahn's algorithm detects cycles naturally: if the finalized order length is less than numCourses, a cycle prevented some in-degrees from reaching 0.

Real-World Scenario & Production Applications

Build dependency task runners (e.g. Bazel/Make/npm package dependency resolvers) and university course curriculum scheduling.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Adjacency List & In-Degree Initialization

Construct directed graph from edge pairs and compute in-degree for every vertex: in_degree[v] = number of prerequisite dependencies.

Mathematical Recurrence / Code Invariant
adj = defaultdict(list)
in_degree = [0] * numCourses
for dest, src in prerequisites:
    adj[src].append(dest)
    in_degree[dest] += 1

Step-by-Step Execution Trace Table

StepQueue BeforeDequeued CourseOrder AppendedDecremented In-DegreesNewly Freed (In-degree 0)Queue After
1[0]0[0]in_degree[1]: 1→0, in_degree[2]: 1→01, 2[1, 2]
2[1, 2]1[0, 1]in_degree[3]: 2→1None (3 still waits on 2)[2]
3[2]2[0, 1, 2]in_degree[3]: 1→03[3]
4[3]3[0, 1, 2, 3]—None[]
Trace InputnumCourses = 2, prerequisites = [[1,0]]
Expected[0,1]
StepQueue BeforeDequeued CourseOrder AppendedDecremented In-DegreesNewly Freed (In-degree 0)Queue After
1[0]0[0]in_degree[1]: 1→0, in_degree[2]: 1→01, 2[1, 2]
2[1, 2]1[0, 1]in_degree[3]: 2→1None (3 still waits on 2)[2]
3[2]2[0, 1, 2]in_degree[3]: 1→03[3]
4[3]3[0, 1, 2, 3]—None[]
Code Shape
Archetype Code Shape
Python
1for dest, src in prerequisites:
2 adj[src].append(dest)
3 in_degree[dest] += 1
4queue = deque(every course with in_degree 0)
5order = []
6while queue:
7 node = queue.popleft()
8 order.append(node)
9 for neighbor in adj[node]:
10 in_degree[neighbor] -= 1
11 if in_degree[neighbor] == 0:
12 queue.append(neighbor)
13return order if len(order) == numCourses else []

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Topological sorting orders vertices in a DAG(Directed Acyclic Graph) such that for every directed edge u→vu \to vu→v, vertex uuu comes before vvv. Kahn's algorithm maintains in-degrees for all nodes. Nodes with in-degree 0 have no prerequisites and are enqueued. As each node is scheduled, outgoing edges are removed. If the final ordered list contains all VVV courses, a valid curriculum order is returned; if not, a circular prerequisite deadlock exists.

📋 The Analogy: Peeling Off Tasks With No Blockers

Imagine a to-do list where every task lists which other tasks must finish first. You scan the whole list once and pull out every task that has zero blockers — those can start immediately, in any order. Every time you finish a task, you go tell everyone who was waiting on it "one of your blockers is done" — and the moment a waiting task's blocker count hits zero, it joins the ready pile too. If you ever run out of ready tasks while some are still stuck waiting, those remaining tasks must be blocking each other in a cycle — an impossible schedule.

🔑 The Key Idea in the Code

len(order) == num_nodes at the end is the cycle detector: if every node were eventually reachable, all of them would eventually hit zero in-degree and get processed — anything left unprocessed must be stuck in a mutual dependency loop.

  • Silent partial order return on directed cycles: Returning the accumulated order array without verifying len(order) == numCourses. If a cycle exists, Kahn's algorithm terminates early; returning a partial order fails the problem requirement to return an empty array [].

  • Reversed prerequisite dependency edge: For prerequisite pair [a, b], course bbb must be taken before aaa. The directed edge is b→ab \to ab→a, and the in-degree of aaa must increase. Reversing this (a→ba \to ba→b) generates an inverted topological order.

  • Disconnected component queue seeding: Only enqueueing course 0 instead of finding all courses with in_degree[i] == 0. Unconnected courses or multiple entry points will never be processed.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Each pair [ai, bi] says course bi must be completed "before" course ai, and you must produce "one valid order" for all courses, or an empty list when "no order can complete every course". Prerequisites plus an order plus "impossible" point to Topological Sort.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Every node in order or in queue comes after all of its prerequisites, and in_degree[v] counts the prerequisites of v not yet in order. The decision: node joins queue at the moment in_degree[node] reaches 0.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • return order if len(order) == num_courses else []: courses on a cycle never reach 0, so a shorter order means no valid order exists; returning the partial order is wrong.

  • for dest, src in prerequisites: [a, b] means b before a, so the edge is b -> a (adj[src].append(dest)) and in_degree[dest] goes up; reversed, the order comes out backwards.

  • queue = deque([i for i in range(num_courses) if in_degree[i] == 0]): seed every course with no prerequisites, not just course 0, or courses in other groups never start.

The 60-Second Interview Pitch

Say this out loud before you type a single line

This is Topological Sort with Kahn's algorithm. Each pair b before a is an edge from b to a, so I build the adjacency list and count every course's in-degree, the prerequisites it still waits for. I put every course with in-degree zero in a queue. Each time I pop a course, I add it to the order and lower the count of every course it unlocks; a course whose count reaches zero joins the queue. That is correct because a course only enters the queue once all its prerequisites are already in the order. The trap is the cycle: courses on a cycle never reach zero, so if the order is shorter than the number of courses I return an empty list, never the partial order. Every course is queued once and every prerequisite is read twice, so it's O(V plus E) time and space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(V + E)

Look at the code: for dest, src in prerequisites reads each of the E pairs once to build adj and in_degree, O(E); seeding queue scans the V counts, O(V). In while queue, every course is popped at most once (it is pushed only when its count reaches 0, which happens once), and for neighbor in adj[node] walks each edge once over the whole run. Total O(V + E).

SPACE COMPLEXITY

O(V + E)

adj stores every edge, O(V + E); in_degree, queue and order hold at most V entries each, O(V). There is no recursion, so the call stack is O(1). order is also the output, V entries.

Formal Recurrence Relation

T(V, E) = E (build) + V (seed) + V (pops) + E (count updates) = O(V + E)

Derivation Progression

Graph build

for dest, src in prerequisites: adj[src].append(dest); in_degree[dest] += 1 → E steps

Each prerequisite pair is read once and does O(1) work.

Seed the queue

deque([i for i in range(num_courses) if in_degree[i] == 0]) → V checks

One pass over the V counts.

Peel

while queue: node = queue.popleft(); for neighbor in adj[node]: in_degree[neighbor] -= 1 → V pops + E decrements

A course is pushed only when its count reaches 0, once, so there are at most V pops; across all pops the inner loop walks each edge once.

Variable Definitions

VVV

Number of courses, num_courses (nodes)

EEE

Number of prerequisite pairs (edges)

Memory Architecture & Bounds

🟣 Call Stack

O(1): no recursion

🔵 Auxiliary Heap

O(V + E): adj holds every edge; in_degree and queue hold V entries

🟢 Output Space

O(V): order

Boundary Best / Worst Cases

Best Case

O(V+E)O(V + E)O(V+E)

Average Case

O(V+E)O(V + E)O(V+E)

Worst Case

O(V+E)O(V + E)O(V+E)

Graph & Tree Traversal Frontier

Graph & Tree Traversal Frontier
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "must be completed before", "one valid order", "return an empty list" when no order exists. An order that respects every prerequisite, plus a report of impossibility: Topological Sort. At scale the same shape is any dependency graph that has to be processed in order: builds, migrations, task pipelines.

CONSTRAINTS & BOUNDS

V≤2000V \le 2000V≤2000 courses, E≤V(V−1)E \le V(V - 1)E≤V(V−1) pairs. Budget: O(V+E)O(V + E)O(V+E) steps and memory for adj (every edge) plus three arrays of VVV. On a graph too large for one machine, adj is the part to shard; in_degree is one counter per node.

FAANG PRODUCTION TRAPS & EDGE CASES

Nodes left out of order are exactly the nodes on or behind a cycle: report them (not just "impossible") so the cycle can be found. A node listed as a prerequisite but never defined is a separate error to check before sorting.

Core Algorithmic State Invariants

  1. Any Valid Order Is Accepted

LC 210 accepts any order that respects every prerequisite. Kahn's queue gives one of them; which one depends on the order courses enter queue, so a different but valid answer is still correct.

  1. Popped Order Is Also a Schedule of Rounds

The courses in queue at one moment have no prerequisite between them. Processing queue one level at a time (as in Level-Order BFS) gives the fewest rounds when courses of one round can be taken together.

Theory Context•Graph Algorithms
MediumLC 210

Course Schedule II (LeetCode 210)

Target Frequency:MetaAmazonGoogleApple

You have numCourses courses to complete, numbered 0 through numCourses - 1, and a list prerequisites where each entry [ai, bi] means course bi must be completed before course ai.

  • So an entry [0, 1] means course 1 has to be finished before course 0.

Produce one valid order in which all courses can be taken; any correct order is acceptable. If no order can complete every course, return an empty list instead.

Worked Examples

Example 1
Input:numCourses = 2, prerequisites = [[1,0]]
Output:[0,1]
Explanation: Course 1 depends on course 0, so 0 must come first, giving the order [0, 1].
Example 2
Input:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
Output:[0,2,1,3]
Explanation: Course 3 depends on both 1 and 2, and each of those depends on course 0. Any order that places 0 first and 3 last works, e.g. [0, 1, 2, 3] or [0, 2, 1, 3].
Example 3
Input:numCourses = 1, prerequisites = []
Output:[0]
Explanation: There is one course with no prerequisites, so the order is just [0].

⚖️Formal Constraints & Bounds

  • 1 <= numCourses <= 2000

  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)

  • prerequisites[i].length == 2

  • 0 <= ai, bi < numCourses

  • ai != bi

  • All the pairs [ai, bi] are distinct

Deep-Dive & Conceptual Insights

Core Insight

Kahn's algorithm detects cycles naturally: if the finalized order length is less than numCourses, a cycle prevented some in-degrees from reaching 0.

Real-World Scenario & Production Applications

Build dependency task runners (e.g. Bazel/Make/npm package dependency resolvers) and university course curriculum scheduling.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Adjacency List & In-Degree Initialization

Construct directed graph from edge pairs and compute in-degree for every vertex: in_degree[v] = number of prerequisite dependencies.

Mathematical Recurrence / Code Invariant
adj = defaultdict(list)
in_degree = [0] * numCourses
for dest, src in prerequisites:
    adj[src].append(dest)
    in_degree[dest] += 1

Step-by-Step Execution Trace Table

StepQueue BeforeDequeued CourseOrder AppendedDecremented In-DegreesNewly Freed (In-degree 0)Queue After
1[0]0[0]in_degree[1]: 1→0, in_degree[2]: 1→01, 2[1, 2]
2[1, 2]1[0, 1]in_degree[3]: 2→1None (3 still waits on 2)[2]
3[2]2[0, 1, 2]in_degree[3]: 1→03[3]
4[3]3[0, 1, 2, 3]—None[]
Trace InputnumCourses = 2, prerequisites = [[1,0]]
Expected[0,1]
StepQueue BeforeDequeued CourseOrder AppendedDecremented In-DegreesNewly Freed (In-degree 0)Queue After
1[0]0[0]in_degree[1]: 1→0, in_degree[2]: 1→01, 2[1, 2]
2[1, 2]1[0, 1]in_degree[3]: 2→1None (3 still waits on 2)[2]
3[2]2[0, 1, 2]in_degree[3]: 1→03[3]
4[3]3[0, 1, 2, 3]—None[]
Code Shape
Archetype Code Shape
Python
1for dest, src in prerequisites:
2 adj[src].append(dest)
3 in_degree[dest] += 1
4queue = deque(every course with in_degree 0)
5order = []
6while queue:
7 node = queue.popleft()
8 order.append(node)
9 for neighbor in adj[node]:
10 in_degree[neighbor] -= 1
11 if in_degree[neighbor] == 0:
12 queue.append(neighbor)
13return order if len(order) == numCourses else []

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Topological sorting orders vertices in a DAG(Directed Acyclic Graph) such that for every directed edge u→vu \to vu→v, vertex uuu comes before vvv. Kahn's algorithm maintains in-degrees for all nodes. Nodes with in-degree 0 have no prerequisites and are enqueued. As each node is scheduled, outgoing edges are removed. If the final ordered list contains all VVV courses, a valid curriculum order is returned; if not, a circular prerequisite deadlock exists.

📋 The Analogy: Peeling Off Tasks With No Blockers

Imagine a to-do list where every task lists which other tasks must finish first. You scan the whole list once and pull out every task that has zero blockers — those can start immediately, in any order. Every time you finish a task, you go tell everyone who was waiting on it "one of your blockers is done" — and the moment a waiting task's blocker count hits zero, it joins the ready pile too. If you ever run out of ready tasks while some are still stuck waiting, those remaining tasks must be blocking each other in a cycle — an impossible schedule.

🔑 The Key Idea in the Code

len(order) == num_nodes at the end is the cycle detector: if every node were eventually reachable, all of them would eventually hit zero in-degree and get processed — anything left unprocessed must be stuck in a mutual dependency loop.

  • Silent partial order return on directed cycles: Returning the accumulated order array without verifying len(order) == numCourses. If a cycle exists, Kahn's algorithm terminates early; returning a partial order fails the problem requirement to return an empty array [].

  • Reversed prerequisite dependency edge: For prerequisite pair [a, b], course bbb must be taken before aaa. The directed edge is b→ab \to ab→a, and the in-degree of aaa must increase. Reversing this (a→ba \to ba→b) generates an inverted topological order.

  • Disconnected component queue seeding: Only enqueueing course 0 instead of finding all courses with in_degree[i] == 0. Unconnected courses or multiple entry points will never be processed.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Each pair [ai, bi] says course bi must be completed "before" course ai, and you must produce "one valid order" for all courses, or an empty list when "no order can complete every course". Prerequisites plus an order plus "impossible" point to Topological Sort.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Every node in order or in queue comes after all of its prerequisites, and in_degree[v] counts the prerequisites of v not yet in order. The decision: node joins queue at the moment in_degree[node] reaches 0.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • return order if len(order) == num_courses else []: courses on a cycle never reach 0, so a shorter order means no valid order exists; returning the partial order is wrong.

  • for dest, src in prerequisites: [a, b] means b before a, so the edge is b -> a (adj[src].append(dest)) and in_degree[dest] goes up; reversed, the order comes out backwards.

  • queue = deque([i for i in range(num_courses) if in_degree[i] == 0]): seed every course with no prerequisites, not just course 0, or courses in other groups never start.

The 60-Second Interview Pitch

Say this out loud before you type a single line

This is Topological Sort with Kahn's algorithm. Each pair b before a is an edge from b to a, so I build the adjacency list and count every course's in-degree, the prerequisites it still waits for. I put every course with in-degree zero in a queue. Each time I pop a course, I add it to the order and lower the count of every course it unlocks; a course whose count reaches zero joins the queue. That is correct because a course only enters the queue once all its prerequisites are already in the order. The trap is the cycle: courses on a cycle never reach zero, so if the order is shorter than the number of courses I return an empty list, never the partial order. Every course is queued once and every prerequisite is read twice, so it's O(V plus E) time and space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(V + E)

Look at the code: for dest, src in prerequisites reads each of the E pairs once to build adj and in_degree, O(E); seeding queue scans the V counts, O(V). In while queue, every course is popped at most once (it is pushed only when its count reaches 0, which happens once), and for neighbor in adj[node] walks each edge once over the whole run. Total O(V + E).

SPACE COMPLEXITY

O(V + E)

adj stores every edge, O(V + E); in_degree, queue and order hold at most V entries each, O(V). There is no recursion, so the call stack is O(1). order is also the output, V entries.

Formal Recurrence Relation

T(V, E) = E (build) + V (seed) + V (pops) + E (count updates) = O(V + E)

Derivation Progression

Graph build

for dest, src in prerequisites: adj[src].append(dest); in_degree[dest] += 1 → E steps

Each prerequisite pair is read once and does O(1) work.

Seed the queue

deque([i for i in range(num_courses) if in_degree[i] == 0]) → V checks

One pass over the V counts.

Peel

while queue: node = queue.popleft(); for neighbor in adj[node]: in_degree[neighbor] -= 1 → V pops + E decrements

A course is pushed only when its count reaches 0, once, so there are at most V pops; across all pops the inner loop walks each edge once.

Variable Definitions

VVV

Number of courses, num_courses (nodes)

EEE

Number of prerequisite pairs (edges)

Memory Architecture & Bounds

🟣 Call Stack

O(1): no recursion

🔵 Auxiliary Heap

O(V + E): adj holds every edge; in_degree and queue hold V entries

🟢 Output Space

O(V): order

Boundary Best / Worst Cases

Best Case

O(V+E)O(V + E)O(V+E)

Average Case

O(V+E)O(V + E)O(V+E)

Worst Case

O(V+E)O(V + E)O(V+E)

Graph & Tree Traversal Frontier

Graph & Tree Traversal Frontier
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "must be completed before", "one valid order", "return an empty list" when no order exists. An order that respects every prerequisite, plus a report of impossibility: Topological Sort. At scale the same shape is any dependency graph that has to be processed in order: builds, migrations, task pipelines.

CONSTRAINTS & BOUNDS

V≤2000V \le 2000V≤2000 courses, E≤V(V−1)E \le V(V - 1)E≤V(V−1) pairs. Budget: O(V+E)O(V + E)O(V+E) steps and memory for adj (every edge) plus three arrays of VVV. On a graph too large for one machine, adj is the part to shard; in_degree is one counter per node.

FAANG PRODUCTION TRAPS & EDGE CASES

Nodes left out of order are exactly the nodes on or behind a cycle: report them (not just "impossible") so the cycle can be found. A node listed as a prerequisite but never defined is a separate error to check before sorting.

Core Algorithmic State Invariants

  1. Any Valid Order Is Accepted

LC 210 accepts any order that respects every prerequisite. Kahn's queue gives one of them; which one depends on the order courses enter queue, so a different but valid answer is still correct.

  1. Popped Order Is Also a Schedule of Rounds

The courses in queue at one moment have no prerequisite between them. Processing queue one level at a time (as in Level-Order BFS) gives the fewest rounds when courses of one round can be taken together.

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•