#721. Accounts Merge
題目描述
給你一個account
列表,列表中的每個account[i]
元素都是字串列表,字串列表中的第一個元素account[i][0]
是名字,後面的元素則是帳號的email。
現在,我們想要合併這些帳號。兩個帳號的email如果有重複,則這兩個帳號是屬於同一個人的。但如果兩個帳號名字一樣,仍然有可能屬於不同的人但是剛好名字一樣。
每個人都有可能會有好幾個號,但是這些帳號的名字都會是一樣的。
合併完帳號列表後,回傳帳號列表並且將帳號用以下格式呈現:第一個元素為帳號名字,剩下的元素是被按照順序排列後的email。帳號可以以不同的順序排列。
限制條件
- 1 <= accounts.length <= 1000
- 2 <= accounts[i].length <= 10
- 1 <= accounts[i][j].length <= 30
accounts[i][0]
只會由英文字母組成。accounts[i][j]
(j > 0) 都是符合格式的email。
解題思路
題目說一個人有多組Email,而且可能會出現同時有好幾筆屬於同一個人的資料,想要合併這些資料,就必須確認資料是屬於同一個人的,因此兩筆資料之間必須要存在共同的Email,才能達成合併條件。
而在最一開始,我們不會知道哪些資料是相關的,所以最開始,先把個人資料劃分成一個Group,並且給Email加上一個Group的Tag用來區分,然後將Email放入Hashtable中作為檢查紀錄。
當處理到某個Email時,這個Email可能在過去曾經標記過了,我們可以在Hashtable的紀錄中找到,那麼這代表這個Email的所屬Group跟我們正在處理的Group是一樣的,所以我們在完成當前Group的同時,也要把記錄中的Email的Group所包含的其他Email都轉移到當前的Group中,這樣就完成了合併。
public class Solution {
public class GroupNode{
public int Num;
public string Owner;
public List<Email> mails;
public GroupNode(int num, string owner){
Num = num;
Owner = owner;
mails = new List<Email>();
}
}
public class Email{
public int Group;
public string Address;
public Email(int group, string address){
Group = group;
Address = address;
}
}
public IList<IList<string>> AccountsMerge(IList<IList<string>> accounts) {
int groupNum = 0;
var nodes = new Hashtable();
var recorded_mails = new Hashtable();
foreach(var account in accounts){
var node = new GroupNode(groupNum,account[0]);
for(int i=1;i<account.Count;i++){
var mail = new Email(groupNum,account[i]);
if(recorded_mails.Contains(mail.Address)){
var num = ((Email) recorded_mails[mail.Address]).Group;
var prev_node = (GroupNode)nodes[num];
// if(num == groupNum) continue;
if(prev_node==null) continue;
foreach(var m in prev_node.mails){
m.Group = groupNum;
node.mails.Add(m);
}
nodes.Remove(num);
}else{
recorded_mails.Add(mail.Address,mail);
}
if(node.mails.Find((ele)=>ele.Address==mail.Address) == null) node.mails.Add(mail);
}
nodes.Add(groupNum,node);
groupNum++;
}
var ans = new List<IList<string>>();
foreach(DictionaryEntry node in nodes){
var group = (GroupNode)node.Value;
var accountName=group.Owner;
var list = new List<string>();
foreach(var i in group.mails) list.Add(i.Address);
list.Sort((a,b)=>String.CompareOrdinal(a,b));
list.Insert(0,accountName);
ans.Add(list);
}
return ans;
}
}
複雜度分析:
- 時間複雜度:Account的數量為n,帳戶中最長的Account長度為m,所以總郵件數量為n * m,處理完合併後,還需要對所有郵件進行整理,會花費Log n * m的時間,因此時間複雜度為O(n * m * log n * m)。
- 空間複雜度:會建立空間存放整理過後的帳戶與郵件,因此空間複雜度為O(n * m)。
學習重點
- Disjoint Set Union (DSU)