基本資料#
難易度: medium 第一次嘗試: 2025-05-12
- 總花費時間:20:00.00
解題思路#
這是一道沒有明確提供關係的並查集(Union Find)問題。
一開始,我採用暴力解法:遍歷每一對帳號並比較它們的 email 集合。
如果他們有超過一個共同元素(例如相同名字且至少一個 email 相同),就將它們 union 起來。
但這個方法的時間複雜度是 O(n²),還需要額外的邏輯來追蹤用戶名稱並避免 email 重複,結果導致程式又亂又慢。
更好、更有效率的方法是建立一個 email 到 index 的對應表。
每次遇到一個 email,我們檢查它是否已經出現在 map 裡:
- 如果有,將目前的帳號與 map 中對應的帳號 index 做 union。
- 如果沒有,就將這個 email 記錄在 map 中,指向目前的帳號 index。
這樣我們只對有共同 email 的帳號做 union,就不需要重複比較整份帳號清單。
最後,我們可以根據 email map,用 root index 來分組 emails,並用 accounts[idx][0]
補上用戶名稱。
關鍵觀念:
- 利用 email 對應到帳號 index 來建立聯繫。
- 並查集僅對 index 運作,不需要對 email 字串做 union。
- union 後以 root index 為基礎進行分組。
時間複雜度:#
- 第一種方法:O(n² * m),其中 m 為每個帳號平均 email 數。
- 第二種方法:O(n·α(n)),α 為阿克曼函數的反函數。
空間複雜度:#
- O(n + m),來自對應表與並查集結構。
解法#
Compare all email account#
我想在這種做法中,我卡在了「共同項目」這個問題上。
我之前從沒想到可以直接把所有 email 當作鍵來處理,當發現某個 email 已經被另一個人使用(透過 index 連結)時,就可以使用並查集(Union Find)來將這兩個帳號連接起來。
class Solution:
def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
n = len(accounts)
uf = UF(n)
for i in range(n):
for j in range(i+1, n):
if len(set(accounts[i]) & set(accounts[j]))>1:
uf.union(i, j)
result = defaultdict(set)
account = []
for i in range(n):
group = uf.find(i)
if result[group] == set():
account.append(accounts[i][0])
result[group].update(accounts[i][1:])
return [[acc, *sorted(value)] for acc, value in zip(account, result.values())]
class UF:
def __init__(self, n):
self.parent = [i for i in range(n)]
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x, y):
root_x = self.find(x)
root_y = self.find(y)
if root_x == root_y:
return
self.parent[root_y] = root_x
iterate through email account#
class UF:
def __init__(self,n):
self.root = list(range(n))
def find(self,x):
if x == self.root[x]:
return x
self.root[x] = self.find(self.root[x])
return self.root[x]
def union(self,x,y):
rootX = self.find(x)
rootY = self.find(y)
if rootX != rootY:
self.root[rootX] = rootY
class Solution:
def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
n = len(accounts)
uf = UF(n)
owner = {}
for idx,(_,*emails) in enumerate(accounts):
for e in emails:
if e in owner:
uf.union(idx,owner[e])
else:
owner[e] = idx
result = defaultdict(list)
for email,num in owner.items():
root = uf.find(num)
result[root].append(email)
return [[accounts[idx][0]] + sorted(email) for idx,email in result.items()]