Python 3.11+
The examples use standard Python containers and syntax available in the supported browser runtime; Disjoint Set Union itself is taught as an interview abstraction.
Verify in Python docs(opens in a new tab)Partition structure supporting near-constant-time connectivity queries through find and union. This guide turns that contract into deliberate Python operations, interview invariants, and a runnable practice loop.
Recognize it when
Consider Disjoint Set Union when the prompt's constraints and required operations match this shape: Partition structure supporting near-constant-time connectivity queries through find and union.

Sign in to save your code and progress across devices. The lesson and problem statement remain public.
Disjoint Set Union maintains a partition of nodes into non-overlapping components. Each component is
represented by one root; two nodes are connected exactly when find returns the same root.
Initially every node is its own parent. Only roots may become children during union. Parent pointers encode membership, while root size or rank guides which representative remains.
find follows parents to a root, then rewrites visited parents toward that root. Compression changes
shape but never component membership.
def compress_all(parent):
compressed = parent.copy()
def find(node):
if compressed[node] != node:
compressed[node] = find(compressed[node])
return compressed[node]
roots = [find(node) for node in range(len(compressed))]
return roots, compressedImplement compress_all(parent). Return roots for every node and a copied parent array compressed directly to roots.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
Attach the smaller root below the larger and update size only at the surviving root. With path compression, a sequence of operations has inverse-Ackermann amortized time, effectively constant for interview-scale inputs.
def disjoint_set_trace(node_count, operations):
parent = list(range(node_count))
size = [1] * node_count
def find(node):
while parent[node] != node:
parent[node] = parent[parent[node]]
node = parent[node]
return node
results = []
for operation, left, right in operations:
left_root, right_root = find(left), find(right)
if operation == 'connected':
results.append(left_root == right_root)
elif left_root != right_root:
if size[left_root] < size[right_root]:
left_root, right_root = right_root, left_root
parent[right_root] = left_root
size[left_root] += size[right_root]
return resultsImplement disjoint_set_trace(node_count, operations) with union by size and path compression; return connected-query booleans.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
Choose DSU for incremental undirected connectivity, cycle checks while adding edges, or Kruskal. Choose DFS/BFS when actual paths, distances, directed reachability, or component contents are needed.
Define root identity, then separate correctness (same root means same component) from optimizations (compression and size). State amortized complexity across the complete operation sequence.
Trace Disjoint-Set Connectivity(opens in a new tab) isolates operations; Number of Islands(opens in a new tab) is usually simpler with traversal unless cells arrive dynamically.
Python 3.11+
The examples use standard Python containers and syntax available in the supported browser runtime; Disjoint Set Union itself is taught as an interview abstraction.
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 |
|---|---|---|---|
| Core Disjoint Set Union workflow | O((n + m) alpha(n)) | O((n + m) alpha(n)) | Maintain parent and component-size arrays, find compressed roots, and attach the smaller root to the larger. |
O(n) for the demonstrated Disjoint Set Union workflow.
These are the mistakes most likely to survive a happy-path example and fail a boundary case.
Placeholder code cannot preserve the Disjoint Set Union invariant or satisfy the public contract.
Prevent it: Implement the smallest complete transition and run the public tests before adding optimizations.
Avoid
def disjoint_set_trace(node_count, operations):
passUse instead
def disjoint_set_trace(node_count, operations):
parent = list(range(node_count))
size = [1] * node_count
results = []
def find(node):
while parent[node] != node:
parent[node] = parent[parent[node]]
node = parent[node]
return node
for operation, left, right in operations:
if operation == "union":
left_root, right_root = find(left), find(right)
if left_root == right_root:
continue
if size[left_root] < size[right_root]:
left_root, right_root = right_root, left_root
parent[right_root] = left_root
size[left_root] += size[right_root]
elif operation == "connected":
results.append(find(left) == find(right))
return resultsWhere you will hit this: Trace Disjoint-Set Connectivity(opens in a new tab)
Compares immediate parent entries rather than roots, so transitive connectivity queries can return false.
Prevent it: Keep this invariant visible while editing: State the precise Disjoint Set Union invariant before coding and preserve it after every update, traversal step, or recursive return.
Avoid
def disjoint_set_trace(node_count, operations):
parent = list(range(node_count))
results = []
for operation, left, right in operations:
if operation == "union":
parent[right] = left
else:
results.append(parent[left] == parent[right])
return resultsUse instead
def disjoint_set_trace(node_count, operations):
parent = list(range(node_count))
size = [1] * node_count
results = []
def find(node):
while parent[node] != node:
parent[node] = parent[parent[node]]
node = parent[node]
return node
for operation, left, right in operations:
if operation == "union":
left_root, right_root = find(left), find(right)
if left_root == right_root:
continue
if size[left_root] < size[right_root]:
left_root, right_root = right_root, left_root
parent[right_root] = left_root
size[left_root] += size[right_root]
elif operation == "connected":
results.append(find(left) == find(right))
return resultsWhere you will hit this: Trace Disjoint-Set Connectivity(opens in a new tab)
Handle empty state, duplicate values, aliasing, and serialization boundaries explicitly in tests.
Prevent it: Account for every slice, copy, sort, membership test, and container mutation before claiming O((n + m) alpha(n)).
Avoid
def disjoint_set_trace(node_count, operations):
parent = list(range(node_count))
results = []
for operation, left, right in operations:
if operation == "union":
parent[right] = left
else:
results.append(parent[left] == parent[right])
return resultsUse instead
def disjoint_set_trace(node_count, operations):
parent = list(range(node_count))
size = [1] * node_count
results = []
def find(node):
while parent[node] != node:
parent[node] = parent[parent[node]]
node = parent[node]
return node
for operation, left, right in operations:
if operation == "union":
left_root, right_root = find(left), find(right)
if left_root == right_root:
continue
if size[left_root] < size[right_root]:
left_root, right_root = right_root, left_root
parent[right_root] = left_root
size[left_root] += size[right_root]
elif operation == "connected":
results.append(find(left) == find(right))
return resultsWhere you will hit this: Number of Islands(opens in a new tab)
Official Python documentation supports language behavior. Canonical problem pages provide additional practice context.
python-docs · checked 2026-07-27