Accounts Merge – Solution & Complexity

Solution Walkthrough

  1. Step 1: See the connectivity pattern

    • If two rows share an email, they belong to the same connected component.
    • The overlap can be indirect, so you need component merging rather than only pairwise merging.
  2. Step 2: Brute-force baseline

    • Compare every pair of rows to see whether they share any email, then repeatedly merge overlapping groups.
    • That repeated scanning is much too slow once many accounts and emails exist.
  3. Step 3: Union rows by shared emails

    • Map each email to the first row that contained it.
    • When the same email appears again, union the current row with the previous owner row.
  4. Step 4: Final solution (all languages)

    Union-find builds connected account components, then a deterministic sort finishes the output contract.

    def accounts_merge(accounts: list[list[str]]) -> list[list[str]]:
        parent = list(range(len(accounts)))
        rank = [0] * len(accounts)
    
        def find(node: int) -> int:
            while node != parent[node]:
                parent[node] = parent[parent[node]]
                node = parent[node]
            return node
    
        def union(a: int, b: int) -> None:
            root_a = find(a)
            root_b = find(b)
            if root_a == root_b:
                return
            if rank[root_a] < rank[root_b]:
                root_a, root_b = root_b, root_a
            parent[root_b] = root_a
            if rank[root_a] == rank[root_b]:
                rank[root_a] += 1
    
        email_owner: dict[str, int] = {}
        for index, account in enumerate(accounts):
            for email in account[1:]:
                if email in email_owner:
                    union(index, email_owner[email])
                else:
                    email_owner[email] = index
    
        grouped: dict[int, list[str]] = {}
        for email in email_owner:
            root = find(email_owner[email])
            grouped.setdefault(root, []).append(email)
    
        merged: list[list[str]] = []
        for root, emails in grouped.items():
            emails.sort()
            merged.append([accounts[root][0], *emails])
    
        merged.sort(key=lambda row: (row[0], row[1]))
        return merged
  5. Step 5: Complexity summary

    • Union-find work is effectively near-linear in the number of email occurrences.
    • Sorting the merged email lists dominates the final deterministic formatting cost.

FAQ