Given a list accounts
, each element accounts[i]
is a list of strings, where the first element accounts[i][0]
is a name, and the rest of the elements are emails representing emails of the account.
Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.
After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.
Example 1:
Input: accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]] Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]] Explanation: The first and third John's are the same person as they have the common email "johnsmith@mail.com". The second John and Mary are different people as none of their email addresses are used by other accounts. We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], ['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.
Note:
The length ofaccounts
will be in the range
[1, 1000]
.The length of
accounts[i]
will be in the range
[1, 10]
.The length of
accounts[i][j]
will be in the range
[1, 30]
思路:第一想法是用hashmap, 不过貌似是我想太简单了,做了大半小时没做出来,就看了大神们的思路,fine, union-find, 我还不会,学呗。
看了好几篇,这个讲的不错:https://www.cnblogs.com/SeaSky0606/p/4752941.html
首先我们遍历每个账户和其中的所有邮箱,先将每个邮箱的root映射为其自身,然后将owner赋值为用户名。然后开始另一个循环,遍历每一个账号,首先对帐号的第一个邮箱调用find函数,得到其父串p,然后遍历之后的邮箱,对每个遍历到的邮箱先调用find函数,将其父串的root值赋值为p,这样做相当于将相同账号内的所有邮箱都链接起来了。我们下来要做的就是再次遍历每个账户内的所有邮箱,先对该邮箱调用find函数,找到父串,然后将该邮箱加入该父串映射的集合汇总,这样就我们就完成了合并。最后只需要将集合转为字符串数组,加入结果res中,通过owner映射找到父串的用户名,加入字符串数组的首位置,参见代码:
class Solution {
public List<List<String>> accountsMerge(List<List<String>> accounts) {
List<List<String>> res = new ArrayList<List<String>>();
Map<String, String> owner = new HashMap<>();
Map<String, String> parents = new HashMap<>();
Map<String, TreeSet<String>> unions = new HashMap<>();
for(List<String>a : accounts){// 初始化。
for(int i=1;i < a.size();i++){
parents.put(a.get(i), a.get(i));
owner.put(a.get(i), a.get(0));
}
}
for(List<String>a : accounts){// 将每个邮箱绑定到其父串
String p = find(a.get(1), parents);
System.out.print(p);
for(int i=2;i<a.size();i++){
parents.put(find(a.get(i), parents),p);
}
}
for(List<String> a : accounts){ //完成了合并
String p = find(a.get(1), parents);
if(!unions.containsKey(p)) unions.put(p, new TreeSet<>());
for(int i = 1; i < a.size(); i++){
unions.get(p).add(a.get(i));
}
}
for (String p : unions.keySet()) {
List<String> emails = new ArrayList(unions.get(p));
emails.add(0, owner.get(p));
res.add(emails);
}
return res;
}
public String find(String p, Map<String, String> parent) {
while(p != parent.get(p)) {
//path compression
parent.put(p, parent.get(parent.get(p)));
p = parent.get(p);
System.out.print("2 "+p);
}
return p;
}
}