Built the adjacency list first, then looped through unvisited nodes and ran DFS from each one, incrementing a counter per traversal.
Start by clarifying the problem constraints (e.g., graph size, edge list format) and then present two standard approaches: Union-Find (Disjoint Set Union) and DFS/BFS. Compare their trade-offs in terms of time and space complexity, and then implement one, ideally Union-Find with path compression and union by rank for optimal performance.
Pro tip: Mention that Union-Find with path compression and union by rank achieves near O(α(n)) per operation, which is practically constant, and that this approach is often preferred in production systems for dynamic connectivity. Also, discuss how to handle edge cases like isolated nodes or empty graphs.
Ask about constraints: number of nodes, number of edges, whether the graph is guaranteed to be connected, and if there are any memory or time limits. Confirm the input format (e.g., edges as pairs of integers).
Explain that connected components can be found using DFS/BFS or Union-Find. Compare their time complexities: DFS/BFS O(n + e) time and O(n) space; Union-Find O(e α(n)) time and O(n) space. Mention that Union-Find is better for dynamic graphs.
Select Union-Find for its efficiency and simplicity. Describe the data structures: parent array, rank/size array. Explain union by rank and path compression optimizations.
Write code for Union-Find: initialize parent[i] = i, rank[i] = 0. For each edge, union the two nodes. Finally, count the number of distinct roots (or decrement a counter on each successful union).
State time complexity O(e α(n)) and space O(n). Walk through a small example to verify correctness, including edge cases like no edges (n components) or a fully connected graph (1 component).
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.