Question presented to candidate: "Given a directed graph with n vertices and a list of edges, group the vertices into strongly connected components, where every vertex in a group can reach every other one. Walk me through an O(V + E) approach and code it in Python."
What a strong answer should cover:
- The definition: u and v are in the same SCC exactly when u reaches v and v reaches u; SCCs partition the vertices, and every directed cycle lies inside one SCC.
- Why the naive approach (a BFS or DFS from every vertex, then compare reachability) is O(V Β· (V + E)), and that linear-time algorithms exist.
- Kosaraju: DFS to record finish order, then DFS the reversed graph in decreasing finish order; each tree of the second pass is one SCC. Or Tarjan: one DFS with discovery indices, low-links and a stack.
- The condensation: contracting each SCC to one node gives a DAG, which is what makes SCCs useful (topological order, 2-SAT, dependency groups).
- Python specifics: adjacency as a list of lists; recursive DFS is fine for small inputs but hits the default recursion limit of 1000 (a 100 000-vertex path raised
RecursionError), so production code uses an explicit stack, orsys.setrecursionlimitwith care.
Clarifying questions expected:
- "Can there be self-loops or duplicate edges? Are the vertices numbered 0 to n - 1?"
- "How large can the graph be? Is deep recursion a concern?"
- "Should the components come out in any particular order?"
Code / implementation expected: Yes β Kosaraju or Tarjan in Python, returning the list of components; an iterative version is a strong bonus.