Python 3.11+
The code uses standard Python syntax and containers supported by the browser Judge. The Kahn's Algorithm proof does not depend on a minor Python release.
Verify in Python docs(opens in a new tab)Produce a topological order by repeatedly removing zero-indegree vertices with a queue. Learn the algorithm's preconditions, state transition, correctness argument, Python cost model, and transfer from one focused drill to a full Interview Problem.
Recognize it when
Consider Kahn's Algorithm when the prompt's constraints and required operations match this shape: Produce a topological order by repeatedly removing zero-indegree vertices with a queue.

Sign in to save your code and progress across devices. The lesson and problem statement remain public.
Kahn’s algorithm starts by computing indegree for every node from every directed edge. Indegree represents unresolved prerequisites, including duplicate edges if the input permits them.
Every node with zero unresolved prerequisites is ready. Seeding all of them is required to cover disconnected DAG components and isolated vertices.
import heapq
def kahn_trace(node_count,edges):
adjacency=[[] for _ in range(node_count)];indegree=[0]*node_count
for source,target in edges:adjacency[source].append(target);indegree[target]+=1
ready=[n for n in range(node_count) if indegree[n]==0];heapq.heapify(ready);trace=[]
while ready:
node=heapq.heappop(ready)
for neighbor in adjacency[node]:
indegree[neighbor]-=1
if indegree[neighbor]==0:heapq.heappush(ready,neighbor)
trace.append([node,indegree.copy(),sorted(ready)])
return traceImplement kahn_trace(node_count,edges). Return [removed,indegree,ready] after each queue removal using ascending ready order.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
When a ready node is processed, decrement each outgoing neighbor once. Enqueue a neighbor exactly when its indegree becomes zero, never before and never repeatedly.
from collections import deque
def kahn_order(node_count,edges):
adjacency=[[] for _ in range(node_count)];indegree=[0]*node_count
for source,target in edges:adjacency[source].append(target);indegree[target]+=1
queue=deque(node for node in range(node_count) if indegree[node]==0);order=[]
while queue:
node=queue.popleft();order.append(node)
for neighbor in adjacency[node]:
indegree[neighbor]-=1
if indegree[neighbor]==0:queue.append(neighbor)
return order if len(order)==node_count else []Implement kahn_order(node_count,edges). Return ascending-ready order or [] if a cycle prevents processing all nodes.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
If the queue empties before V nodes are processed, the remaining subgraph has no zero-indegree node and therefore contains a directed cycle. The algorithm takes O(V + E) time and space.
Say: “Indegree counts unresolved prerequisites. Zero-indegree nodes are safe next choices; removing one resolves each outgoing prerequisite. If processed count is short, a cycle blocked the rest.” State how ready-node ordering affects deterministic output.
Python 3.11+
The code uses standard Python syntax and containers supported by the browser Judge. The Kahn's Algorithm proof does not depend on a minor Python release.
Verify in Python docs(opens in a new tab)Interview bounds depend on the stated representation, input model, and real Python operations.
| Operation | Average | Worst | Interview note |
|---|---|---|---|
| Kahn's Algorithm complete workflow | O(V log V + E) | O(V log V + E) | Dependency graphs expose currently available work as the nodes with zero remaining incoming edges. A node enters a frontier exactly when all of its predecessors have been removed, and each edge decrements indegree once. |
O(V + E) for the focused Maintain an Indegree Frontier implementation.
These are the mistakes most likely to survive a happy-path example and fail a boundary case.
Verify algorithm preconditions such as sorted input, nonnegative weights, acyclicity, or admissible heuristics before applying it.
Prevent it: State and verify this precondition before coding: Dependencies form a directed graph, and a complete ordering exists only when the graph is acyclic.
Avoid
def kahn_frontier_layers(node_count, edges):
passUse instead
def kahn_frontier_layers(node_count, edges):
graph = [[] for _ in range(node_count)]
indegree = [0] * node_count
for before, after in edges:
graph[before].append(after)
indegree[after] += 1
frontier = [node for node, degree in enumerate(indegree) if degree == 0]
layers = []
processed = 0
while frontier:
frontier.sort()
layers.append(frontier)
next_frontier = []
for node in frontier:
processed += 1
for neighbor in graph[node]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0:
next_frontier.append(neighbor)
frontier = next_frontier
return layers if processed == node_count else []Where you will hit this: Maintain an Indegree Frontier(opens in a new tab)
Returns partial layers without verifying that every node was processed, so directed cycles are accepted.
Prevent it: Preserve this proof obligation: Only zero-indegree vertices are emitted, so every prerequisite precedes each dependent; a short result reveals a cycle.
Avoid
def kahn_frontier_layers(node_count, edges):
graph = [[] for _ in range(node_count)]
indegree = [0] * node_count
for before, after in edges:
graph[before].append(after); indegree[after] += 1
frontier = [i for i, degree in enumerate(indegree) if degree == 0]
layers = []
while frontier:
layers.append(sorted(frontier)); next_frontier = []
for node in frontier:
for neighbor in graph[node]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0: next_frontier.append(neighbor)
frontier = next_frontier
return layersUse instead
def kahn_frontier_layers(node_count, edges):
graph = [[] for _ in range(node_count)]
indegree = [0] * node_count
for before, after in edges:
graph[before].append(after)
indegree[after] += 1
frontier = [node for node, degree in enumerate(indegree) if degree == 0]
layers = []
processed = 0
while frontier:
frontier.sort()
layers.append(frontier)
next_frontier = []
for node in frontier:
processed += 1
for neighbor in graph[node]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0:
next_frontier.append(neighbor)
frontier = next_frontier
return layers if processed == node_count else []Where you will hit this: Maintain an Indegree Frontier(opens in a new tab)
Include visited state, boundary cases, recursion depth, and hidden copying costs in correctness and complexity analysis.
Prevent it: Count every sort, slice, copy, membership check, heap update, and recursive frame before claiming O(V log V + E).
Avoid
def kahn_frontier_layers(node_count, edges):
graph = [[] for _ in range(node_count)]
indegree = [0] * node_count
for before, after in edges:
graph[before].append(after); indegree[after] += 1
frontier = [i for i, degree in enumerate(indegree) if degree == 0]
layers = []
while frontier:
layers.append(sorted(frontier)); next_frontier = []
for node in frontier:
for neighbor in graph[node]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0: next_frontier.append(neighbor)
frontier = next_frontier
return layersUse instead
def kahn_frontier_layers(node_count, edges):
graph = [[] for _ in range(node_count)]
indegree = [0] * node_count
for before, after in edges:
graph[before].append(after)
indegree[after] += 1
frontier = [node for node, degree in enumerate(indegree) if degree == 0]
layers = []
processed = 0
while frontier:
frontier.sort()
layers.append(frontier)
next_frontier = []
for node in frontier:
processed += 1
for neighbor in graph[node]:
indegree[neighbor] -= 1
if indegree[neighbor] == 0:
next_frontier.append(neighbor)
frontier = next_frontier
return layers if processed == node_count else []Where you will hit this: Course Schedule(opens in a new tab)
Official Python documentation supports language behavior. Canonical problem pages provide additional practice context.
python-docs · checked 2026-07-12
python-docs · checked 2026-07-27