Python 3.11+
The code uses standard Python syntax and containers supported by the browser Judge. The Union-Find proof does not depend on a minor Python release.
Verify in Python docs(opens in a new tab)Maintain dynamic components using path-compressed find and union by rank or size. 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 Union-Find when the prompt's constraints and required operations match this shape: Maintain dynamic components using path-compressed find and union by rank or size.

Sign in to save your code and progress across devices. The lesson and problem statement remain public.
Union-find stores a parent forest where each component has one root that parents itself. Two nodes are connected exactly when find returns the same root.
Path compression rewires visited nodes toward the root, preserving component identity while accelerating later queries. Apply it consistently in recursive or iterative find.
def union_find_trace(n,edges):
parent=list(range(n));size=[1]*n;trace=[]
def find(node):
while node!=parent[node]:parent[node]=parent[parent[node]];node=parent[node]
return node
for left,right in edges:
a,b=find(left),find(right);merged=a!=b
if merged:
if size[a]<size[b]:a,b=b,a
parent[b]=a;size[a]+=size[b]
trace.append([parent.copy(),size.copy(),merged])
return traceImplement union_find_trace(n,edges). Return [parent,size,merged] after each union using path compression and union by size.
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
Union by size or rank attaches the shallower structure under the stronger root. Update metadata only on roots and only when two distinct components actually merge.
def first_redundant_edge(n,edges):
parent=list(range(n));size=[1]*n
def find(node):
if parent[node]!=node:parent[node]=find(parent[node])
return parent[node]
for left,right in edges:
a,b=find(left),find(right)
if a==b:return [left,right]
if size[a]<size[b]:a,b=b,a
parent[b]=a;size[a]+=size[b]
return []Implement first_redundant_edge(n,edges). Return the first edge whose endpoints are already connected, or [].
Loading interactive editor.If it does not appear, the reference and starter code remain readable.Reload editor
Union-find excels at edge additions and repeated connectivity queries, with near-constant amortized operations. It does not directly support deletions, shortest paths, or component traversal; graph search is better for those.
Say: “Parent roots identify components. Find compresses paths, union attaches the smaller root, and an edge between equal roots is redundant.” State O((n + m) alpha(n)) time and O(n) space.
Python 3.11+
The code uses standard Python syntax and containers supported by the browser Judge. The Union-Find 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 |
|---|---|---|---|
| Union-Find complete workflow | O((n + e) alpha(n)) | O((n + e) alpha(n)) | Use path-compressed find and union by size while maintaining a component counter. |
O(n) for the focused Count Components with Union-Find 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: Connectivity can be represented by stable element identities and component merges.
Avoid
def component_count(node_count, edges):
passUse instead
def component_count(node_count, edges):
parent = list(range(node_count))
size = [1] * node_count
def find(node):
while node != parent[node]:
parent[node] = parent[parent[node]]
node = parent[node]
return node
count = node_count
for left, right in edges:
a, b = find(left), find(right)
if a == b:
continue
if size[a] < size[b]:
a, b = b, a
parent[b] = a
size[a] += size[b]
count -= 1
return countWhere you will hit this: Count Components with Union-Find(opens in a new tab)
Decrements for every edge, including edges within one component.
Prevent it: Preserve this proof obligation: Parent links preserve equivalence classes, while compression and balancing change representation but not membership.
Avoid
def component_count(n,edges):
return n-len(edges)Use instead
def component_count(node_count, edges):
parent = list(range(node_count))
size = [1] * node_count
def find(node):
while node != parent[node]:
parent[node] = parent[parent[node]]
node = parent[node]
return node
count = node_count
for left, right in edges:
a, b = find(left), find(right)
if a == b:
continue
if size[a] < size[b]:
a, b = b, a
parent[b] = a
size[a] += size[b]
count -= 1
return countWhere you will hit this: Count Components with Union-Find(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((n + e) alpha(n)).
Avoid
def component_count(n,edges):
return n-len(edges)Use instead
def component_count(node_count, edges):
parent = list(range(node_count))
size = [1] * node_count
def find(node):
while node != parent[node]:
parent[node] = parent[parent[node]]
node = parent[node]
return node
count = node_count
for left, right in edges:
a, b = find(left), find(right)
if a == b:
continue
if size[a] < size[b]:
a, b = b, a
parent[b] = a
size[a] += size[b]
count -= 1
return countWhere 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-27