Accounts Merge

MediumUnion-Find · Graph Components🧩 Union-FindLeetCode #721 ↗Updated

Problem

Each entry of accounts is a list whose first element is a person's name and whose remaining elements are email addresses. Two accounts belong to the same person if they share at least one email (possibly through a chain of accounts); equal names alone prove nothing. Merge them and return each person as [name, emails sorted lexicographically, no duplicates], in any order.
Input[["Ann","a1@x.com","a2@x.com"],["Ann","a3@x.com","a1@x.com"],["Bob","b@x.com"],["Ann","a9@x.com"]]Output[["Ann","a1@x.com","a2@x.com","a3@x.com"],["Bob","b@x.com"],["Ann","a9@x.com"]]
Input[["Cy","c1@y","c2@y"],["Cy","c3@y"],["Cy","c2@y","c3@y"]]Output[["Cy","c1@y","c2@y","c3@y"]] (merged through a chain)

1 ≤ accounts.length ≤ 1000  ·  2 ≤ accounts[i].length ≤ 10  ·  emails sharing an owner always have the same name

Try it yourself

Java
class Solution {
    public List<List<String>> accountsMerge(List<List<String>> accounts) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
“Shares an email, directly or through a chain” is just connectivity. Union every account with the first account that owned each of its emails; each resulting set is one person, whose emails are then sorted.
PatternUnion-Find

Instinct Items get grouped by "connected", "same as" or "shares a" links and you keep asking which group something is in: merge sets with Union-Find.

Memory hack Find your boss, merge the bosses; squash the chain (path compression) and hang the short tree under the tall one (rank).

Open the Union-Find guide →

Approaches

Brute ForcePairwise Account Comparison + DFS

Time O(n2·k + N log N)Space O(n2 + N)

Turn each account into a set of emails and compare every pair of accounts (O(k) per pair with hash sets); overlapping pairs become edges between accounts. Each connected component of accounts is one person. Here n = accounts, k = emails per account, N = total emails.

Java
public List<List<String>> accountsMerge(List<List<String>> accounts) {
    int n = accounts.size();
    List<Set<String>> sets = new ArrayList<>();
    for (List<String> acc : accounts) sets.add(new HashSet<>(acc.subList(1, acc.size())));
    List<List<Integer>> adj = new ArrayList<>();
    for (int i = 0; i < n; i++) adj.add(new ArrayList<>());
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (!Collections.disjoint(sets.get(i), sets.get(j))) {
                adj.get(i).add(j);
                adj.get(j).add(i);
            }
        }
    }
    boolean[] seen = new boolean[n];
    List<List<String>> result = new ArrayList<>();
    for (int i = 0; i < n; i++) {
        if (seen[i]) continue;
        TreeSet<String> emails = new TreeSet<>();
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(i);
        seen[i] = true;
        while (!stack.isEmpty()) {
            int u = stack.pop();
            emails.addAll(sets.get(u));
            for (int v : adj.get(u)) {
                if (!seen[v]) {
                    seen[v] = true;
                    stack.push(v);
                }
            }
        }
        List<String> merged = new ArrayList<>();
        merged.add(accounts.get(i).get(0));
        merged.addAll(emails);
        result.add(merged);
    }
    return result;
}

Simple, but the n2 pair checks dominate for many accounts.

At a glance

LevelApproachTimeSpace
Brute ForcePairwise Account Comparison + DFSO(n2·k + N log N)O(n2 + N)
BetterEmail Graph + DFSO(N log N)O(N)
OptimalUnion-Find over AccountsO(N·α(n) + N log N)O(N)
Common pitfalls
  • Merging accounts just because the names match — two different people can share a name.
  • Only merging direct overlaps — chains (A~B, B~C) must collapse into one person.
  • Leaving duplicate emails or forgetting to sort them before prepending the name.
Interview tips
  • Reframe as “connected components where shared emails are edges”.
  • Mention the star trick: n-1 edges per account, not a full clique.
  • Note that sorting dominates, so DFS and union-find are equally fast asymptotically.
Pattern
Union-Find / connected components → group records that are linked transitively by any shared key.
My notes saved in this browser