◀ THE GRIND — GRAPHS

Accounts Merge

MEDIUM✓ CHIP-TIMEDLC #721 — FULL STATEMENT ↗

The drill: Each account lists an owner's name and the emails they signed up with. The same person can show up as several accounts sharing at least one email — merge every account into one per real person, name plus every distinct email, sorted.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

A list of accounts arrives, each one holding an owner's name followed by every email address registered under that account. The same real person can show up as multiple separate accounts, connected by sharing at least one email in common.

Two accounts belong to the same person exactly when their email lists overlap — directly, or through a chain of other accounts bridging them together. The name on an account can't be trusted alone, since two different real people might share the same printed name.

The task is to merge every account into one per actual person: that person's name, followed by every distinct email they've ever used, sorted alphabetically. The merged accounts themselves can come back in any order.

EX 01
accounts = [["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["John", "johnsmith@mail.com", "john00@mail.com"], ["Mary", "mary@mail.com"], ["John", "johnnybravo@mail.com"]]
[["John", "john00@mail.com", "john_newyork@mail.com", "johnsmith@mail.com"], ["Mary", "mary@mail.com"], ["John", "johnnybravo@mail.com"]]
ONE SHARED EMAIL MERGES TWO JOHNS; A THIRD JOHN STAYS SEPARATE
EX 02
accounts = [["Alice", "alice1@mail.com", "alice2@mail.com"], ["Bob", "bob1@mail.com"]]
[["Alice", "alice1@mail.com", "alice2@mail.com"], ["Bob", "bob1@mail.com"]]
NO SHARED EMAILS AT ALL, NOTHING MERGES
EX 03
accounts = [["A", "a1@x.com"]]
[["A", "a1@x.com"]]
A SINGLE ACCOUNT, SINGLE EMAIL
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

Two accounts belong to the same person exactly when they share at least one email — the name printed on the account can't be trusted alone, since two different people can share a name.

HINT 2 THE STRUCTURE

Think of every email as a node, and each account as a set of edges tying its emails together. Merging accounts is really finding which emails end up in the same connected cluster.

HINT 3 ONE STEP FROM THE ANSWER

Union every pair of emails inside the same account. Afterward, group all emails by their root, attach whichever account's name owns that root, sort each group's emails, and that's one merged account.

COACH'S BOARD — THE PATTERN, STEP BY STEP
MERGING BY SHARED EMAILPATTERN · UNION-FIND ON EMAILSJohn=[j1,j2], John=[j1,j3], Mary=[m1]
STEP 1

3 accounts arrive: two labeled John share email j1, one labeled Mary stands alone. Union each account's emails against its first email.

STEP 1 / 6 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/accounts-merge.pyRACE PACE
LANG ▸
PACE ▸
class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        parent = {}
        owner = {}

        def find(x):
            parent.setdefault(x, x)
            while parent[x] != x:
                parent[x] = parent[parent[x]]
                x = parent[x]
            return x

        def union(a, b):
            ra, rb = find(a), find(b)
            if ra != rb:
                parent[ra] = rb

        for acc in accounts:
            name = acc[0]
            first = acc[1]
            for email in acc[1:]:
                owner[email] = name
                union(first, email)

        groups = collections.defaultdict(list)
        for email in owner:
            groups[find(email)].append(email)

        return [[owner[root]] + sorted(emails) for root, emails in groups.items()]
TIME O(N·K·Α(N·K))SPACE O(N·K)PYTHON · RACE PACE · 29 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED