LeetCode -721 账户合并

在这里插入图片描述
在这里插入图片描述

class Solution {
    Map<Integer,Integer> unionMap = new HashMap<Integer,Integer>();
    Map<String,List<Integer>> muMap = new HashMap<String,List<Integer>>();//每个邮箱地址对应的用户
    public List<List<String>> accountsMerge(List<List<String>> accounts) {
          //初始化并查集
          //将每个账户在accounts中的下标作为其标识
          for(int i = 0;i < accounts.size();i++)
              unionMap.put(i,i);//将每个账户的祖先设为其自己
          //将每一个邮箱地址对应的所有用户放入muMap 如果一个邮箱地址对应了多个用户 这些用户就应该进行合并
          for(int i = 0;i < accounts.size(); i++)
          {
              List<String> list = accounts.get(i);
              for(int j=1;j<list.size();j++){
                  if(muMap.get(list.get(j)) == null )
                     muMap.put(list.get(j),new ArrayList<Integer>());
                   List<Integer> list1 =  muMap.get(list.get(j));
                   list1.add(i); 
                   if(list1.size()>=2)//邮箱对应了至少两个账户时将它们合并
                   {
                        int x = list1.get(list1.size()-1);
                        int y = list1.get(list1.size()-2);
                        x = findRoot(x);
                        y = findRoot(y);
                        if(x != y)
                        {
                            if(x < y)
                               unionMap.put(y,x);
                            else
                               unionMap.put(x,y);
                        }
                   }
                    
              }
          }
        // 此时已经完成了并查集的建立
        Map<Integer,Queue<String>> ans = new HashMap<Integer,Queue<String>>();
        for(int i = 0;i < accounts.size(); i++)
        {
            int root = findRoot(i);
            if(ans.get(root) == null)
               ans.put(root,new PriorityQueue<String>());
            Queue<String> queue = ans.get(root);
            for(int j = 1;j<accounts.get(i).size();j++){
                queue.offer(accounts.get(i).get(j));
            }
        }
        List<List<String>> rans = new ArrayList<List<String>>();
        for(Map.Entry<Integer,Queue<String>> map : ans.entrySet())
        {
            int index = map.getKey();
            Queue<String> queue = map.getValue();
            List<String> list = new ArrayList<>();
            list.add(accounts.get(index).get(0));
            while(queue.size()!=0){
                String str = queue.poll();
                if(str.equals(list.get(list.size()-1))==false)
                   list.add(str);
            }
            rans.add(list);
        }
        return rans;
    }
    public int findRoot(int x){
        if(unionMap.get(x) == x)
          return x;
        else
         return findRoot(unionMap.get(x));
    }
}
class Solution {
    public List<List<String>> accountsMerge(List<List<String>> accounts) {
        //建立一个 根据邮箱地址到Index的映射
        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);
            //得到当前遍历账户下List的长度
            int size = account.size();
            //通过此长度对接下来的邮箱进行遍历
            for (int i = 1; i < size; i++) {
                //得到当前i时的 邮箱地址
                String email = account.get(i);
                //看邮箱对应Index中是否有这个邮箱地址,保证每个邮箱的唯一性
                if (!emailToIndex.containsKey(email)) {
                    //如果没有出现过这个邮箱,将它添加到两个对应的map中
                    emailToIndex.put(email, emailsCount++);
                    emailToName.put(email, name);
                }
            }
        }
        //此时两个Map中分别存储了每个邮箱以及它对应的Index,每个邮箱它对应的户主名字。接下来建立并查集
        UnionFind uf = new UnionFind(emailsCount);
        //遍历account
        for (List<String> account : accounts) {
            //得到当前account下第一个邮箱的地址,根据地址得到索引,把它作为根
            String firstEmail = account.get(1);
            int firstIndex = emailToIndex.get(firstEmail);
            //得到当前account下的邮箱个数进行遍历
            int size = account.size();
            for (int i = 2; i < size; i++) {
                //得到需要进行合并操作的邮箱地址,因为对于同一账户,他们都属于一个人,因此把他们合并
                String nextEmail = account.get(i);
                //根据邮箱地址从映射中取出Index
                int nextIndex = emailToIndex.get(nextEmail);
                //合并操作
                uf.union(firstIndex, nextIndex);
            }
        }
        //通过上面的操作,首先将同一个账户中的每个邮箱指向根邮箱,后续
        //在其他的账户中遇到了相同的邮箱,在接着合并操作,此时对应根节点的个数就是总用户数

        //建立一个Index对应邮箱地址的Map
        Map<Integer, List<String>> indexToEmails = new HashMap<Integer, List<String>>();
        //通过emailToIndex遍历邮箱地址
        for (String email : emailToIndex.keySet()) {
            //根据索引在并查集中得到当前邮箱地址的根节点
            int index = uf.find(emailToIndex.get(email));
            //判断是否存在根节点,没有就创建一个ArrrayList,有的话就获取当前的ArrayList
            List<String> account = indexToEmails.getOrDefault(index, new ArrayList<String>());
            //在当前的List中加入现邮箱地址,因为他们有同一个根
            account.add(email);
            //更新indexToEmails的邮箱列表
            indexToEmails.put(index, account);
        }
        //创建答案表,按要求对答案进行整理
        List<List<String>> merged = new ArrayList<List<String>>();
        //通过indexToEmail的值(values)进行遍历
        for (List<String> emails : indexToEmails.values()) {
            //将emails按照题目要求进行排序
            Collections.sort(emails);
            //得到当前邮箱组的根,然后根据根得到用户名字
            String name = emailToName.get(emails.get(0));
            //创建一个account表
            List<String> account = new ArrayList<String>();
            //首先添加用户名字,然后用addAll将emails表整个添加到account中
            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];
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值