Leetcode刷题笔记 721. 账户合并

721. 账户合并

知识点:并查集
时间:2021年1月18日
题目链接

题目

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

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

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

示例 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']] 也是正确的

提示

  • accounts的长度将在[1,1000]的范围内。
  • accounts[i]的长度将在[1,10]的范围内。
  • accounts[i][j]的长度将在[1,30]的范围内。

解题思路

  1. 用hashmap存储 邮箱和人的对应关系
  2. 遍历所有邮箱 如果这个邮箱第一次出现 则放入hashmap中 这个邮箱属于用户 这里用户用所对应的下标表示 省去再次构建 用户转换成int类型
  3. 如果这个邮箱已经出现过了 则合并这个用户对应下标 和 之前出现过的邮箱对应的用户下标 说明这两个是同一个用户
  4. 遍历所有用户和邮箱 找到祖先节点 把用户和邮箱关联起来放在 hashmap<int,set> 中 最后转换为答案

代码

#include "cheader.h"
class Solution {
public:
    struct UN{
        vector<int> ancestor;
        UN(int x){
            ancestor.resize(x);
            for(int i = 0;i < x;i++)
                ancestor[i] = i;
        }
        int find(int x){
            if(ancestor[x] == x)
                return x;
            else
                return  ancestor[x] = find(ancestor[x]);
        }
        void merge(int a, int b){
            ancestor[find(a)] = find(b);
        }
    };
    vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
        unordered_map<string, int> um;
        int n = accounts.size();
        UN un = UN(n);
        for(int i = 0; i< n; i++){
            for(int j = 1; j< accounts[i].size(); j++){
                if(um.find(accounts[i][j]) == um.end())
                    um[accounts[i][j]] = i; //记录mail对应的下标
                else
                    un.merge(i, um[accounts[i][j]]);//如果出现过,合并i和上一次出现的位置
            }
        }
        
        unordered_map<int, set<string>> umans;
        for(int i = 0; i< n; i++){
            int parent = un.find(i); //找到父节点
            for(int j = 1;j < accounts[i].size(); j++)
                umans[parent].insert(accounts[i][j]); //有相同邮箱的人 他们对应的下标属于一个连通分量 他们所有的邮箱放在一起
        }
        
        vector<vector<string>> ans;
        for(auto it:umans){
            vector<string> tmp;
            tmp.push_back(accounts[it.first][0]);
            for(string mail:it.second)
                tmp.push_back(mail);
            ans.push_back(tmp);
        }
        
        return ans;
    }
};
int main()
{
    vector<vector<string>> accounts;
    accounts.push_back(vector<string>{"John", "johnsmith@mail.com", "john00@mail.com"});
    accounts.push_back(vector<string>{"John", "johnnybravo@mail.com"});
    accounts.push_back(vector<string>{"John", "johnsmith@mail.com", "john_newyork@mail.com"});
    accounts.push_back(vector<string>{"Mary", "mary@mail.com"});
    Solution s;
    vector<vector<string>> ans = s.accountsMerge(accounts);
    for(vector<string> x:ans){
        for(string str:x)
            cout<<str<<" ";
        cout<<endl;
    }
    return 0;
}

今天也是爱zz的一天哦!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值