Leetcode.721账户合并

Leetcode.721账户合并

问题描述:

波波老师您好,这道题我采用了并查集结合哈希表的方法做的,而且通过输出的方式检查过了并查集方法,合并两个字符串集合方法,mailMap<String,Integer>存的是邮箱以及对应的账户id也是正确的,我觉得应该是最后遍历一遍账户,将id对应的账户信息与id根节点对应的账户信息连接的时候发生了数据的丢失,请问一下老师标记第5部分的代码是不是存在问题

相关代码:

​import java.util.*;

class Solution {

public int[] parent;
public int[] rank;

public Solution(){}

//传入账户的数量
public Solution(int size) {
parent = new int[size];
rank = new int[size];
for (int i = 0; i < size; i++) {
parent[i] = i;
rank[i] = 1;
}
}

/**
*Find!
*/
public int find(int p) {
while (p != parent[p]) {
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}

public boolean isConnected(int p, int q) {
return find(p) == find(q);
}

public void text() {
for (int i = 0; i < parent.length; i++) {
System.out.println("parent[" + i + "]=" + parent[i]);
}
}

/**
* Union!
*/
public void union(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot) {
return;
}
if (rank[pRoot] < rank[qRoot]) {
parent[pRoot] = qRoot;
} else if (rank[qRoot] < rank[pRoot]) {
parent[qRoot] = pRoot;
}else {
parent[pRoot] = qRoot;
rank[qRoot] += 1;
}
}

/**
* 上面实现完并查集***************************************
*/

public List<List<String>> accountsMerge(List<List<String>> accounts) {
//1.判断输入是否为空
if (accounts == null || accounts.size() == 0) {
return null;
}

//2.获取传入账户的数量 第i个账户的id就是i
int accountNumber = accounts.size();

//3.为每一个账户id创建并查集
Solution uniFind = new Solution(accountNumber);

//4.创建邮箱与账户id之间的哈希表
HashMap<String, Integer> mailMap = new HashMap<>();
//遍历每一个账户 如果邮箱已经存储在哈希表中 在并查集进行连接
for (int i = 0; i < accountNumber; i++) {
List<String> account = accounts.get(i);//获取id为i的账户
int size = account.size();//获取当前邮箱有多少个字符串

for (int j = 1; j < size; j++) {
//第一个字符串是名字 后面的元素才是邮箱
//判断当前的邮箱哈希表存不存在这个邮箱
String curMail = account.get(j);

if (!mailMap.containsKey(curMail)) {
//如果不存在这个邮箱 直接存入
mailMap.put(curMail, i);
}else{
//如果已经存在将两个账户id并查集连接
uniFind.union(i, mailMap.get(curMail));
}
}
}
// for (Map.Entry<String, Integer> entry : mailMap.entrySet()) {
// System.out.println(entry.getKey() + ", " + entry.getValue());
// }
// uniFind.text();

/**
* 经过上面循环不仅获得所有邮箱对应的账户id,并且将有相同邮箱的账户进行了并查集合并
* ************************************************************
*/

//5.创建id与账户列表的哈希表
HashMap<Integer, List<String>> accountIdMap = new HashMap<>();
//遍历传入的账户链表
for (int i = 0; i < accountNumber; i++) {
//获得当前的账户信息
List<String> curAccount = accounts.get(i);
//获得当前账户id的父节点账户信息
int rootId = uniFind.find(i);

List<String> rootAccount = accounts.get(rootId);
//连接当前的账户与根节点的邮箱
List<String> res = merge(curAccount, rootAccount);
accountIdMap.put(rootId, res);
}

// for (Map.Entry<Integer, List<String>> entry : accountIdMap.entrySet()) {
// System.out.println(entry.getKey() + ": " + entry.getValue());
// }



//获取map有多少key
List<List<String>> res = new LinkedList<>();
for (Map.Entry<Integer, List<String>> entry : accountIdMap.entrySet()) {
res.add(entry.getValue());
}
return res;
}

public List<String> merge(List<String> cur, List<String> root) {
//1.首先获得姓名
String name = cur.get(0);
List<String> res = new LinkedList<>();
res.add(name);
for (String s : cur) {
if (!res.contains(s)) {
res.add(s);
}
}
for (String s : root) {
if (!res.contains(s)) {
res.add(s);
}
}
Collections.sort(res);
return res;
}

public static void main(String[] args) {
Solution solution = new Solution();
List<String> list1 = new LinkedList<>();
list1.add("David");
list1.add("David0@m.co)");
list1.add("David4@m.co)");
list1.add("David3@m.co)");

List<String> list2 = new LinkedList<>();
list2.add("David");
list2.add("David5@m.co)");
list2.add("David5@m.co)");
list2.add("David0@m.co)");

List<String> list3 = new LinkedList<>();
list3.add("David");
list3.add("David1@m.co)");
list3.add("David4@m.co)");
list3.add("David0@m.co)");
List<List<String>> accountsMerge = new LinkedList<>();
accountsMerge.add(list1);
accountsMerge.add(list2);
accountsMerge.add(list3);
System.out.println(solution.accountsMerge(accountsMerge));
List<String> text=solution.merge(list1, list2);
for (String str : text) {
System.out.println(str);
}

}
}


正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

1回答
liuyubobobo 2021-09-03 12:20:39

问题确实发生在你的代码注释的部分 5:


每次,你将 accounts.get(i) 和 rootId 对应的 accounts.get(rootId) 进行合并,得到的结果扔给 accountIdMap[rootId] 对应的地方。


但是,如果有 多个 i 的 root 是 rootId 对应的话,你这样做只能存住一个 i 和 rootId 合并的结果。


我设计了一个小的测试用例,在这个测试用例里,Gabe0 1 2 3 四个邮箱都属于同一个人,但是你的方法将丢掉信息,原因就是处理到最后一个 Gabe 1 2 的时候,把之前处理的 Gabe 2 3 覆盖掉了。你可以尝试单步跟踪一下。


[["Gabe","Gabe0@m.co","Gabe1@m.co"],

["Gabe","Gabe2@m.co","Gabe3@m.co"],

["Gabe","Gabe1@m.co","Gabe2@m.co"]]


继续加油!:)

问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
算法与数据结构
  • 参与学习       2583    人
  • 解答问题       1082    个

慕课网算法名师Liuyubobobo,5年集大成之作 从0到工作5年,算法与数据结构系统解决方案

了解课程
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师