721.账户合并
思路一:哈希表,并查集
鉴于很多邮箱公用一个名字,我们只需要现将同一个人的邮箱汇总在一起,然后最后输出答案的时候,用他的一个邮箱反向查询到他对应的用户的名字即可。
官方源码分析:
class Solution {
public List<List<String>> accountsMerge(List<List<String>> accounts) {
Map<String, Integer> emailToIndex = new HashMap<String, Integer>();
Map<String, String> emailToName = new HashMap<String, String>();
// 第一步:给每个不重复的邮箱一个编号和对应的名字
int emailsCount = 0;
for (List<String> account : accounts) {
String name = account.get(0);
int size = account.size();
for (int i = 1; i < size; i++) {
String email = account.get(i);
if (!emailToIndex.containsKey(email)) {
emailToIndex.put(email, emailsCount++);
emailToName.put(email, name);
}
}
}
// 第二步:将每一条Entry中同一个人的邮箱统计在一起。
UnionFind uf = new UnionFind(emailsCount);
for (List<String> account : accounts) {
String firstEmail = account.get(1);
int firstIndex = emailToIndex.get(firstEmail);
int size = account.size();
for (int i = 2; i < size; i++) {
String nextEmail = account.get(i);
int nextIndex = emailToIndex.get(nextEmail);
uf.union(firstIndex, nextIndex);
}
}
// 第三步:🌟将所有同类的元素合并在一起!类别编号用index表示
Map<Integer, List<String>> indexToEmails = new HashMap<Integer, List<String>>();
// 利用keyset将所有的不重复的email取出来
for (String email : emailToIndex.keySet()) {
int index = uf.find(emailToIndex.get(email)); //找到email对应的类别编号
// 利用getOrDefault,如果indexToEmails中存在index,就返回它存的List<String>,
// 反之就返回一个新的List<>String>;
List<String> account = indexToEmails.getOrDefault(index, new ArrayList<String>());
account.add(email);
indexToEmails.put(index, account);
}
// 第四步:整合为答案
List<List<String>> merged = new ArrayList<List<String>>();
// 得到每一个index对应的email集合
for (List<String> emails : indexToEmails.values()) {
Collections.sort(emails); //因为题目要求对邮箱进行排序
String name = emailToName.get(emails.get(0));
List<String> account = new ArrayList<String>();
account.add(name);
account.addAll(emails);
merged.add(account);
}
return merged;
}
}
class UnionFind {
int[] parent;
public UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public void union(int index1, int index2) {
parent[find(index2)] = find(index1);
}
public int find(int index) {
if (parent[index] != index) {
parent[index] = find(parent[index]);
}
return parent[index];
}
}
自己手写:
收获:
- 可以利用
getOrDefault
创建一个新的HashMap;
如下面的代码,就等同于如果index存在,就取出原来的List<String>
并添加"新元素",
如果index不存在,就为这个新的key index创建一个空的List<String>
并添加“新元素”
最后勿忘更新原来的HashMap。
Map<Integer,List<String>> map = new HashMap<>();
List<String>tmp = map.getOrDefault(index,new ArrayList<String>());
tmp.add("新元素");
map.put(index,tmp);
- 得到所有的key:
.keySet()
,得到每一个key对应的values集合.values()
。 Collections.sort()
可以对List<String>
进行升序排序。