【Leetcode】721. Accounts Merge

题目地址:

https://leetcode.com/problems/accounts-merge/

给定若干以字符串列表表示的账户,第 0 0 0个字符串是用户名,后面是其邮箱。如果两个账户share了某同一个邮箱,那么这两个账户是属于同一个人的。注意,用户名相同不意味着两个账户是属于同一个人的。要求将这些账户做合并,返回新的账户列表,第 0 0 0个字符串也是用户名,后面是其邮箱,并且要求对邮箱按字典序排序。

思路是并查集。将每个账户的所有邮箱合并在同一个集合里,然后将并查集按照祖宗节点归类,这样每一类就属于同一个用户。最后整理返回即可。代码如下:

class Solution {
 public:
  // 并查集的父亲数组
  vector<int> p;
  int idx;
  // 由于我们要整理email的并查集结构,需要将email序列化为数字
  unordered_map<string, int> email_to_int;
  unordered_map<int, string> int_to_email;
  // 存同一个用户的所有email在并查集里的根节点的序列化的值到这个用户的名字的映射
  unordered_map<int, string> name_mp;
  int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }
  void merge(string& x, string& y) {
    if (!email_to_int.count(x)) {
      email_to_int[x] = idx;
      int_to_email[idx++] = x;
    }
    if (!email_to_int.count(y)) {
      email_to_int[y] = idx;
      int_to_email[idx++] = y;
    }
    int px = find(email_to_int[x]), py = find(email_to_int[y]);
    p[px] = py;
  }
  vector<vector<string>> accountsMerge(vector<vector<string>>& as) {
    int cnt = 0;
    for (auto& v : as) cnt += v.size() - 1;
    p.resize(cnt);
    for (int i = 0; i < p.size(); i++) p[i] = i;
    for (auto& acct : as) {
      auto name = acct[0];
      string a1 = acct[1];
      if (acct.size() == 2) merge(a1, a1);
      for (int i = 2; i < acct.size(); i++) merge(acct[i], a1);
      name_mp[find(email_to_int[a1])] = name;
    }

    unordered_map<int, set<string>> group_mp;
    for (auto& acct : as) {
      string a1 = acct[1];
      int pp = find(email_to_int[a1]);
      for (int i = 1; i < acct.size(); i++) group_mp[pp].insert(acct[i]);
    }
    vector<vector<string>> res;
    for (auto& [k, v] : group_mp) {
      vector<string> vv;
      string name = name_mp[k];
      vv.push_back(name);
      vv.insert(vv.end(), v.begin(), v.end());
      res.push_back(vv);
    }
    return res;
  }
};

时间复杂度 O ( n l log ⁡ n ) O(nl\log n) O(nllogn) n n n是字符串总数, l l l是最长字符串长度,空间 O ( n l ) O(nl) O(nl)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值