Leetcode 721. 账户合并 (略有难度比较绕的并查集问题)

这道题目比较有难度,名字允许相同,对应不同的邮箱,邮箱相同一定对应同一个账户,一个账户可能有多个邮箱,

所以如何标记一个账户?直接用编号id

首先我们使用一个HashMap,从邮箱映射到id,一旦发现有相同的邮箱时,就用并查集把id连起来,并查集维护的是id。


但是答案,要求的是id对应邮箱,因此我们需要在建立一个hashmap,里面是id,对应邮箱集合。

我们遍历之前的map,找到邮箱和id,通过并查集将id对应到根节点的id。

然后得到id,邮箱集合数组,由于通过遍历hashmap得到,所以邮箱数组一定不会有重复。

最后,我们再遍历一次id,邮箱数组,然后将数据加入答案数组,这题总体逻辑比较绕,面试中第一次见难度很大。

class Union{
private:
    vector<int> p;
    int n;
public:
    Union(){}
    Union(int n){
        this->n = n;
        p.resize(n);
        for(int i=0;i<n;i++){
            p[i] = i;
        }
    }

    int find(int x){
        if(x!=p[x]) p[x] = find(p[x]);
        return p[x];
    }

    void unite(int x,int y){
        p[find(x)] = find(y);
    }

    bool isUnite(int x, int y){
        return p[x] == p[y];
    }
};

const int N = 2000;

class Solution {
public:
    vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
        vector<vector<string>> res;
        unordered_map<string,int> emailToIndex;    // 用邮箱对应编号,将相同的邮箱连起来
        int n = accounts.size();
        Union un(n);
        
        for(int i=0;i<n;i++){
            for(int j=1;j<accounts[i].size();j++){
                if(emailToIndex.count(accounts[i][j])){
                    un.unite(emailToIndex[accounts[i][j]],i);
                }else{
                    emailToIndex[accounts[i][j]] = i;
                }
            }
        }
        
        
        // 邮箱Id对应账号,只需返过来遍历HashMap
        unordered_map<int,vector<string>> indexToEmail;
        for(auto &[email,index]:emailToIndex){
            indexToEmail[un.find(index)].push_back(email);
        }

        for(auto &[index,emails]:indexToEmail){
            sort(emails.begin(),emails.end());
            vector<string> tmp;
            tmp.push_back(accounts[index][0]);
            for(auto email:emails){
                tmp.push_back(email);
            }
            res.push_back(tmp);
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/wwxy1995/article/details/112797575
今日推荐