Number of Provinces. — Cracked Java
// Data Structures & Algorithms · Union-Find (Disjoint Set Union)
MidCoding

Number of Provinces.

Problem. Given an n × n matrix isConnected where isConnected[i][j] == 1 means city i and city j are directly connected, return the number of provinces — groups of cities connected directly or transitively. This is a connected-components count, the textbook union-find application.

Brute force — DFS/BFS flood fill, O(n²) time

Iterate over unvisited cities; from each, DFS across the adjacency matrix marking everything reachable, incrementing a province counter per new flood. Perfectly valid and O(n²) since the matrix has n² entries. Union-find is the more composable answer and the one this topic is about.

Optimal — union-find, O(n² · α(n)) time, O(n) space

Union every connected pair, then count distinct roots. Below is the reusable DSU class used throughout this topic — both optimizations, a live component count, and a connected helper.

class DSU {
    int[] parent, rank;
    int count;                                    // number of disjoint sets
    DSU(int n) {
        parent = new int[n];
        rank = new int[n];
        count = n;
        for (int i = 0; i < n; i++) parent[i] = i;
    }
    int find(int x) {                             // path compression
        if (parent[x] != x) parent[x] = find(parent[x]);
        return parent[x];
    }
    boolean union(int a, int b) {                 // union by rank
        int ra = find(a), rb = find(b);
        if (ra == rb) return false;               // already in same set
        if (rank[ra] < rank[rb]) { int t = ra; ra = rb; rb = t; }
        parent[rb] = ra;
        if (rank[ra] == rank[rb]) rank[ra]++;
        count--;                                   // one fewer set after a merge
        return true;
    }
    boolean connected(int a, int b) { return find(a) == find(b); }
}

public int findCircleNum(int[][] isConnected) {
    int n = isConnected.length;
    DSU dsu = new DSU(n);
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)            // upper triangle is enough
            if (isConnected[i][j] == 1) dsu.union(i, j);
    return dsu.count;                              // distinct sets = provinces
}

Maintaining count in the DSU (decrement on every real merge) means the answer is O(1) at the end — no final pass to count roots. We scan only the upper triangle because the matrix is symmetric.

Mark your status