Home
Day 4 · Week 1

Connected Components

Level 1 · Fundamentals  ·  2 hrs: ~45 min theory · ~60 min code · ~15 min notes

🧠 Mental Model

A connected component is a maximal group of nodes all reachable from each other. The whole algorithm is a one-liner idea: traversal, applied repeatedly. Start a BFS/DFS from any unvisited node — everything it reaches is one component. Repeat from the next unvisited node. The number of times you start a traversal = the number of components.

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.

⚙️ Mechanics

  1. Keep a global visited set and a count = 0.
  2. Loop over every node. If it's unvisited: increment count, then BFS/DFS from it (marking everything reachable).
  3. When the outer loop ends, count is the number of components.

Three flavors you'll meet

Undirected only: "connected components" is an undirected notion. The directed analogue is strongly connected components (Tarjan's, Week 4) — a much harder beast. Don't conflate them.

📊 Complexity

MetricValueWhy
TimeO(V + E)Every node and edge is visited exactly once across all traversals combined.
SpaceO(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.

💻 Reference Implementation (Java)

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)

⚠️ Common Pitfalls

Incrementing count inside the traversal: the count++ belongs in the outer loop, once per restart — not per node visited.
Isolated nodes forgotten: a node with no edges is still its own component. The outer loop over all nodes handles this — don't loop only over edges.
Applying this to a directed graph: gives "weakly connected"-ish nonsense. For directed strong connectivity you need Tarjan/Kosaraju.

🎭 Problem Variances — how Big Tech disguises components

The tell is "how many groups / clusters," "are these two connected," or "size of a region." Common disguises:

Disguise / phrasingWhat's really askedTwist to handle
"Number of provinces / friend circles / groups"Count componentsBFS/DFS restarts, or Union-Find distinct roots
"Largest region / island size"Max component sizeTrack size per traversal / per root
"Are X and Y in the same group?"Same-component queryLabel nodes (compId) for O(1) queries; or Union-Find
"Connections arrive over time / streaming"Incremental connectivityUnion-Find beats re-running BFS (Day 10)
"Make the graph connected (min edges to add)"components − 1 edges neededCount components, subtract 1
"Group anagrams / accounts by shared key"Components via shared attributeUnion on shared email/key; group by root
"Directed — strongly connected?"NOT this algorithmNeeds Tarjan/Kosaraju (Week 4), not plain traversal
Key distinction: static graph, count once → BFS/DFS. Edges stream in with interleaved queries → Union-Find. "Strongly connected" (directed) is a different, harder problem (Week 4).

🎯 Problems

LC 547 Number of Provinces Adjacency matrix given; count components. Redo with Union-Find in Week 2. Med
LC 323 Number of Connected Components in Undirected Graph The canonical statement — build the list, count restarts. Med
LC 130 Surrounded Regions Flood-fill trick: mark regions connected to the border as safe, flip the rest. Med