Python 3.11+
The code uses standard Python syntax and containers supported by the browser Judge. The Topological Sort proof does not depend on a minor Python release.
Verify in Python docs(opens in a new tab)Order a directed acyclic graph so every dependency appears before its dependents. 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 Topological Sort when the prompt's constraints and required operations match this shape: Order a directed acyclic graph so every dependency appears before its dependents.

Sign in to save your code and progress across devices. The lesson and problem statement remain public.
A topological order lists every vertex of a directed acyclic graph so each edge source appears before its target. It is a precedence contract, not merely a traversal order.
DFS appends a node after all dependencies and reverses postorder. Kahn’s algorithm repeatedly removes zero-indegree nodes. Both take O(V + E), but expose different cycle evidence and ordering controls.
def is_topological_order(node_count,edges,order):
if len(order)!=node_count or len(set(order))!=node_count:return False
position={node:index for index,node in enumerate(order)}
return all(source in position and target in position and position[source]<position[target] for source,target in edges)Implement is_topological_order(node_count,edges,order). Return whether order contains every node once and places each directed edge forward.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
A directed cycle makes every cycle node depend on another cycle node. DFS detects an edge to the active path; Kahn detects that fewer than V nodes were processed.
import heapq
def topological_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
ready=[node for node in range(node_count) if indegree[node]==0];heapq.heapify(ready);order=[]
while ready:
node=heapq.heappop(ready);order.append(node)
for neighbor in adjacency[node]:
indegree[neighbor]-=1
if indegree[neighbor]==0:heapq.heappush(ready,neighbor)
return order if len(order)==node_count else []Implement topological_order(node_count,edges). Return the lexicographically smallest valid order, or [] for a cycle.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
A DAG may have many valid orders. Use a heap when the contract requests lexicographically smallest output; otherwise any deterministic queue or traversal order is acceptable.
Say: “A valid order places every directed edge forward. I remove currently dependency-free nodes and decrement exactly their outgoing edges; processing fewer than V nodes proves a cycle.” Mention isolated nodes and duplicate-edge policy.
Python 3.11+
The code uses standard Python syntax and containers supported by the browser Judge. The Topological Sort 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 |
|---|---|---|---|
| Topological Sort 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: Lowest Common Ancestor in a BST(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