leetcode 721. 账户合并

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

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

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

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

题解
该题非常经典,是一道并查集的题目。题解中用到多种数据结构,集合,哈希表,还要区分list的append和extend的方法,然后如何创建列表字典。ASCII 顺序排列用sort实现,其余具体思路见注释

from collections import defaultdict
class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:

        #1.我们只能根据邮箱名相同来进行合并,如何判断邮箱名是否相同那么就需要一个哈希表作为介质。
        #  找到相同了后,该如何合并呢?这个时候就需要哈希表的value存位置索引才行
        email_dict = {}
        uf = Unionfind(accounts)
        row = len(accounts)
        for i in range(0,row):
            for j in range(1,len(accounts[i])):
                if accounts[i][j] not in email_dict:
                    email_dict[accounts[i][j]] = i
                else:
                    uf.union(i,email_dict[accounts[i][j]])
 

        #2.把根节点作为key,元素作为value构成一个字典,方便下一步合并为一个用户
        #  创建列表字典,即初始化的value为list
        graph = collections.defaultdict(list)
        for i in range(0,row):
            parent = uf.find(i)
            graph[parent].append(i)

        #3.合并同一个根节点的用户的邮箱
        res = []
        for idx, idx_list in graph.items():
            cur = [accounts[idx][0]]
            #用集合这个数据结构,避免加入重复元素
            emails = set()
            for i in idx_list:
                emails.update(accounts[i][1:])
            emails = list(emails) #将集合转为列表
            emails.sort()
            #extend()用于在列表末尾追加另一个序列中的多个值,输入对象为元素队列
            cur.extend(emails)
            res.append(cur)
        return res

class Unionfind:
    def __init__(self,accounts):
        self.root = []
        length = len(accounts)
        self.root = [-1]*length
        for i in range(0,length):
            self.root[i] = i

    def find(self,x):
        if self.root[x] == x:
            return x
        else:
           #用了递归
            self.root[x] = self.find(self.root[x])
            return self.root[x]

    def union(self,x,y):
        rootx = self.find(x)
        rooty = self.find(y)
        if rootx != rooty:
            self.root[rootx] = rooty
            

refer:
题解
Python列表操作中extend和append的区别
列表字典
字典排序

你可能感兴趣的:(刷题,leetcode,算法,数据结构)