This is your first "composite" algorithm: you're not learning something new, you're orchestrating Day 2/3 traversals with an outer loop. Recognizing that "count the groups" = "count traversal restarts" is a mental unlock that pays off through the rest of the course.
visited set and a count = 0.count, then BFS/DFS from it (marking everything reachable).count is the number of components.compId[node]. Enables O(1) "same component?" queries.| Metric | Value | Why |
|---|---|---|
| Time | O(V + E) | Every node and edge is visited exactly once across all traversals combined. |
| Space | O(V) | Visited/label array + traversal stack or queue. |
Note the outer loop does not add a factor — a node visited in an earlier component is skipped, so total work stays linear. Union-Find (Week 2) solves the same problem incrementally and is preferred when edges arrive one at a time.
Count components on an adjacency list, and label each node with its component id.
import java.util.*;
/** Returns number of connected components; fills compId[] with labels. */
public int countComponents(int n, List<Integer>[] adj, int[] compId) {
boolean[] seen = new boolean[n];
int components = 0;
for (int start = 0; start < n; start++) {
if (seen[start]) continue; // already part of a counted component
components++; // a NEW component begins here
dfs(start, adj, seen, compId, components - 1);
}
return components;
}
private void dfs(int u, List<Integer>[] adj,
boolean[] seen, int[] compId, int id) {
seen[u] = true;
compId[u] = id; // label this node
for (int v : adj[u])
if (!seen[v]) dfs(v, adj, seen, compId, id);
}
// Now compId[a] == compId[b] ⇔ a and b are in the same component (O(1) query)
count++ belongs in the outer loop, once per restart — not per node visited.The tell is "how many groups / clusters," "are these two connected," or "size of a region." Common disguises:
| Disguise / phrasing | What's really asked | Twist to handle |
|---|---|---|
| "Number of provinces / friend circles / groups" | Count components | BFS/DFS restarts, or Union-Find distinct roots |
| "Largest region / island size" | Max component size | Track size per traversal / per root |
| "Are X and Y in the same group?" | Same-component query | Label nodes (compId) for O(1) queries; or Union-Find |
| "Connections arrive over time / streaming" | Incremental connectivity | Union-Find beats re-running BFS (Day 10) |
| "Make the graph connected (min edges to add)" | components − 1 edges needed | Count components, subtract 1 |
| "Group anagrams / accounts by shared key" | Components via shared attribute | Union on shared email/key; group by root |
| "Directed — strongly connected?" | NOT this algorithm | Needs Tarjan/Kosaraju (Week 4), not plain traversal |