Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Trees & Graphs

Binary Trees

  • Tree Traversal (DFS & BFS)
  • Binary Search Tree Operations

Graph Algorithms

  • Graph DFS & BFS
  • Topological Sort
  • Union-Find (Disjoint Sets)
Chaturmind
← Trees & Graphs

Binary Trees

  • Tree Traversal (DFS & BFS)
  • Binary Search Tree Operations

Graph Algorithms

  • Graph DFS & BFS
  • Topological Sort
  • Union-Find (Disjoint Sets)
HomeLearnDSATrees, Graphs & Advanced DSAGraph Algorithms
✓ FreeAdvanced· 13 min read

Union-Find (Disjoint Set Union)

Implement Union-Find with path compression and union by rank for near-O(1) connectivity queries.

Published March 14, 2025


Union-Find (Disjoint Set Union)

Union-Find maintains a collection of disjoint sets and supports two operations: union (merge two sets) and find (determine which set an element belongs to). With path compression and union by rank, both operations run in near-O(1) amortized time.

Implementation

class UnionFind {
    private int[] parent;
    private int[] rank;
    private int components;

    public UnionFind(int n) {
        parent = new int[n];
        rank   = new int[n];
        components = n;
        for (int i = 0; i < n; i++) parent[i] = i; // each node is its own parent
    }

    // Find with path compression
    public int find(int x) {
        if (parent[x] != x)
            parent[x] = find(parent[x]); // compress: point directly to root
        return parent[x];
    }

    // Union by rank
    public boolean union(int x, int y) {
        int px = find(x), py = find(y);
        if (px == py) return false; // already in same set
        if (rank[px] < rank[py]) { int tmp = px; px = py; py = tmp; } // swap so px has higher rank
        parent[py] = px;
        if (rank[px] == rank[py]) rank[px]++;
        components--;
        return true; // successfully merged
    }

    public boolean connected(int x, int y) { return find(x) == find(y); }
    public int getComponents() { return components; }
}

Number of Connected Components

public int countComponents(int n, int[][] edges) {
    UnionFind uf = new UnionFind(n);
    for (int[] edge : edges) uf.union(edge[0], edge[1]);
    return uf.getComponents();
}

Redundant Connection

// Find the edge that creates a cycle
public int[] findRedundantConnection(int[][] edges) {
    UnionFind uf = new UnionFind(edges.length + 1);
    for (int[] edge : edges) {
        if (!uf.union(edge[0], edge[1])) return edge; // already connected = cycle edge
    }
    return new int[0];
}

Accounts Merge

// Merge accounts that share an email
public List<List<String>> accountsMerge(List<List<String>> accounts) {
    Map<String, String> emailToName = new HashMap<>();
    Map<String, String> parent = new HashMap<>();

    // Initialize each email as its own parent
    for (List<String> account : accounts) {
        String name = account.get(0);
        for (int i = 1; i < account.size(); i++) {
            parent.putIfAbsent(account.get(i), account.get(i));
            emailToName.put(account.get(i), name);
        }
    }

    // Union all emails in the same account
    for (List<String> account : accounts) {
        String root = account.get(1);
        for (int i = 2; i < account.size(); i++) {
            String px = find(parent, root);
            String py = find(parent, account.get(i));
            parent.put(px, py);
        }
    }

    // Group by root
    Map<String, TreeSet<String>> groups = new HashMap<>();
    for (String email : parent.keySet()) {
        String root = find(parent, email);
        groups.computeIfAbsent(root, k -> new TreeSet<>()).add(email);
    }

    List<List<String>> result = new ArrayList<>();
    for (Map.Entry<String, TreeSet<String>> e : groups.entrySet()) {
        List<String> account = new ArrayList<>();
        account.add(emailToName.get(e.getKey()));
        account.addAll(e.getValue());
        result.add(account);
    }
    return result;
}

Complexity

  • Find with path compression: amortized O(α(n)) — essentially O(1)
  • Union by rank: O(α(n)) — essentially O(1)
  • α is the inverse Ackermann function; for any practical n, α(n) ≤ 4

Interview Tips

  1. Union-Find is optimal for dynamic connectivity — adding edges and querying connectivity.
  2. For static connectivity (no changes after setup), DFS/BFS is equally good.
  3. Always use both path compression AND union by rank — neither alone achieves the amortized O(α(n)) bound.

Previous

Topological Sort

AI Tutor

Lesson: Union-Find (Disjoint Set Union)

Quick actions

AI responses can be inaccurate. Verify critical information.