Leetcode力扣秋招刷题路-0721

文章讲述了如何使用并查集数据结构和哈希表来解决账户合并的问题,其中关键在于通过邮箱地址的共用来判断账户是否属于同一个人。给出的解题思路是建立字符串映射的并查集,遍历所有账户,合并相同用户的邮箱,并在最后整理出符合输出格式的答案。
摘要由CSDN通过智能技术生成

从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结

721. 账户合并

给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0] 是 名称 (name),其余元素是 emails 表示该账户的邮箱地址。

现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。

合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回。

示例 1:
输入:accounts = [[“John”, “johnsmith@mail.com”, “john00@mail.com”], [“John”, “johnnybravo@mail.com”], [“John”, “johnsmith@mail.com”, “john_newyork@mail.com”], [“Mary”, “mary@mail.com”]]
输出:[[“John”, ‘john00@mail.com’, ‘john_newyork@mail.com’, ‘johnsmith@mail.com’], [“John”, “johnnybravo@mail.com”], [“Mary”, “mary@mail.com”]]
解释:
第一个和第三个 John 是同一个人,因为他们有共同的邮箱地址 “johnsmith@mail.com”。
第二个 John 和 Mary 是不同的人,因为他们的邮箱地址没有被其他帐户使用。
可以以任何顺序返回这些列表,例如答案 [[‘Mary’,‘mary@mail.com’],[‘John’,‘johnnybravo@mail.com’],
[‘John’,‘john00@mail.com’,‘john_newyork@mail.com’,‘johnsmith@mail.com’]] 也是正确的。

示例 2:
输入:accounts = [[“Gabe”,“Gabe0@m.co”,“Gabe3@m.co”,“Gabe1@m.co”],[“Kevin”,“Kevin3@m.co”,“Kevin5@m.co”,“Kevin0@m.co”],[“Ethan”,“Ethan5@m.co”,“Ethan4@m.co”,“Ethan0@m.co”],[“Hanzo”,“Hanzo3@m.co”,“Hanzo1@m.co”,“Hanzo0@m.co”],[“Fern”,“Fern5@m.co”,“Fern1@m.co”,“Fern0@m.co”]]
输出:[[“Ethan”,“Ethan0@m.co”,“Ethan4@m.co”,“Ethan5@m.co”],[“Gabe”,“Gabe0@m.co”,“Gabe1@m.co”,“Gabe3@m.co”],[“Hanzo”,“Hanzo0@m.co”,“Hanzo1@m.co”,“Hanzo3@m.co”],[“Kevin”,“Kevin0@m.co”,“Kevin3@m.co”,“Kevin5@m.co”],[“Fern”,“Fern0@m.co”,“Fern1@m.co”,“Fern5@m.co”]]

提示:
1 <= accounts.length <= 1000
2 <= accounts[i].length <= 10
1 <= accounts[i][j].length <= 30
accounts[i][0] 由英文字母组成
accounts[i][j] (for j > 0) 是有效的邮箱地址

解题思路:

本题和用整型作为元素标记的并查集解法是一样的,数组下标表示当前元素,数组下标对应的数组值表示该元素所处的集合,是一种映射关系。这里是字符串来表示元素,对应的字符串表示该元素所处的集合,直接通过哈希表来实现了这种字符串到字符串的映射。

首先通过哈希表建立并查集,哈希表的键值对都是字符串,然后将一个账户中所有的邮箱并查集合并;
利用一个哈希表暂时存储邮箱列表,将所有邮箱存到并查集中根元素对应的列表中;
最后进行输出,遍历上面根元素邮箱列表,进行排序和加入账户名即可。
这题和之前做的这道题是一个套路的,都是用字符串作为并查集的标记元素。

class Solution {
    // 利用一个字符串的映射存储并查集
    Map<String, String> q;
    public List<List<String>> accountsMerge(List<List<String>> accounts) {
        q = new HashMap<>();
        // 这个映射存储每个邮箱对应账户的名字
        Map<String, String> names = new HashMap<>();

        // 遍历所有账户构建并查集
        for(List<String> a : accounts) {
            for(int i = 1; i < a.size(); i++) {
                if(!q.containsKey(a.get(i))){
                    // 如果并查集中没有这个邮箱,则添加邮箱,其根元素就是本身
                    q.put(a.get(i), a.get(i));
                    // 添加该邮箱对应的账户名
                    names.put(a.get(i), a.get(0));
                } 

                if(i > 1) {
                    // 并查集的合并操作,合并一个账户中的所有邮箱
                    q.put(find(a.get(i)), find(a.get(i - 1)));
                }
            }
        }

        // 暂时存储答案中的邮箱列表,每个键值对的键就是每个并查集集合的根元素
        Map<String, List<String>> temp = new HashMap<>();
        for(String email : q.keySet()) {
            // 获取当前邮箱对应并查集的根元素
            String root = find(email);
            // 将当前邮箱放入根元素对应的列表中
            if(!temp.containsKey(root)) temp.put(root, new ArrayList<>());
            temp.get(root).add(email);
        }

        // 将答案从映射中放到列表
        List<List<String>> res = new ArrayList();
        for(String root : temp.keySet()) {
            // 获取当前根元素对应的列表
            List<String> layer = temp.get(root);      
            // 题目要求的排序
            Collections.sort(layer);
            // 添加姓名
            layer.add(0, names.get(root));
            // 将当前列表加入答案
            res.add(layer);
        }

        return res;
    }

    // 并查集查找模板函数,这里用字符串替换了之前的整型
    // find就是一个寻根归祖的方法,寻找当前元素最终将属于哪个根元素,这个根元素来表示一个联通集合
    // 如果x映射的值等于x,那就可以说明x是个根元素,例如一个集合中只有一个元素,那么它当然可以代表自己
    // 这样做可以让一个集合中的所有元素都能直接或者间接指向根元素,一个集合中只有一个元素的映射是本身
    private String find(String x) {
        // 判断x是不是就是一个根元素
        if(!q.get(x).equals(x)) {
            // x不是根,那就通过递归find函数来找到x映射的元素的根元素(寻根)
            // 找到根元素之后,通过put方法将x直接映射到根元素,这样就免去中间的多次递归(归祖)
            q.put(x, find(q.get(x)));
        }

        // 最终,x映射的元素就是x所在的集合的根元素,返回x的根元素
        return q.get(x);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fffffffyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值