cswork / libraryOpen practice workspace

Coding questions · Apple

Implement DFS for connected components

This question evaluates a candidate's ability to implement depth-first search for connected components, covering both recursive and iterative implementations while testing understanding of stack-safety, time and space complexity, and edge-case testing.

Given an undirected graph with n nodes (1 ≤ n ≤ 200, 000) and an edge list, implement depth-first search to compute (a) the number of connected components and (b) the size of the largest component; provide both recursive and iterative implementations; discuss stack-safety for large graphs, time and space complexity, and how you would test edge cases.

Connected Components via DFS

You are given an undirected graph with n nodes labeled from 1 to n, and a list of edges where each edge [a, b] connects node a and node b. Using depth-first search, compute two values:

  • (a) the number of connected components in the graph, and
  • (b) the size (number of nodes) of the largest connected component.

Return the answer as an array of exactly two integers: [number_of_components, size_of_largest_component].

A connected component is a maximal set of nodes such that there is a path between any two nodes in the set. An isolated node (one with no edges) is itself a connected component of size 1.

Example:

n = 5, edges = [[1,2],[2,3],[4,5]]

Components are {1,2,3} (size 3) and {4,5} (size 2), so the answer is [2, 3].

Implement DFS to traverse each component. An iterative (explicit-stack) DFS is preferred over a recursive one here because n can be as large as 200,000 and a deep chain would overflow the call stack — the reference solution below uses the iterative form for stack safety.

Constraints

  • 1 <= n <= 200,000
  • 0 <= number of edges <= n * (n - 1) / 2
  • Nodes are labeled from 1 to n (1-indexed).
  • Edges are undirected; edge [a, b] is the same as [b, a].
  • The graph may contain isolated nodes (counted as components of size 1).
  • Return [number_of_components, size_of_largest_component].

Hints

  1. Build an adjacency list from the edge list so you can traverse each node's neighbors in O(1) amortized time.
  2. Keep a visited array. Iterate over every node 1..n; each time you reach an unvisited node, that's a new component — run a DFS from it and count how many nodes it reaches.
  3. Track the size of each component as you traverse, and keep a running maximum for the largest-component answer.
  4. Prefer an iterative DFS with an explicit stack over recursion: with n up to 200,000, a long path would overflow the recursion call stack.