[英雄星球七月集训LeetCode解题日报] 第26日 并查集

这篇博客介绍了如何使用并查集解决面试题中关于婴儿名字的统计问题。作者首先分享了错误的做法,即在union操作前比较节点字典序,然后改正为在union内部进行路径压缩和比较。博客提到了两种并查集实现,一种基于数组,另一种基于字典,并指出后者在实际测试中表现更好。最后,提供了完整代码实现。
摘要由CSDN通过智能技术生成

[英雄星球七月集训LeetCode解题日报] 第26日 并查集

日报

  • 今日并查集以为是水题结果wa了一次。

题目

一、 面试题 17.07. 婴儿名字

链接: 面试题 17.07. 婴儿名字

1. 题目描述

在这里插入图片描述

2. 思路分析
  • 题面很清晰,其实就是并查集归出所有的祖宗节点(同族字典序最小的单词),然后每个数的频率都统计到祖宗头上。
  • 我wa了一次在于union之前判断x,y的字典序,然后把x合并向y,这样是错误的,因为路径压缩后,x的祖宗和y的祖宗字典序不一定谁大谁小呢,因此要在union内部:x,y都路径压缩后比较祖宗的字典序,然后选择方向合并。
  • 由于我的并查集模板是数组的,因此需要先对单词进行离散化,映射成数字下标进行并查集,比较麻烦。下边打算整理一个基于字典的模板。

  • 实测不离散化更快。
  • 基于字典的并查集要注意,findfather和union之前,把x,y都setdefault本身
    在这里插入图片描述
3. 代码实现

原答案

class UnionFind:
    def __init__(self,size):
        self.fathers = list(range(size))
    def find_father(self,x):
        return self._zip_find_father(x)    
    def _zip_find_father(self,x):
        fathers = self.fathers
        if fathers[x] != x:
            fathers[x] = self._zip_find_father(fathers[x])
        return fathers[x]                      
    def union(self,x,y):
        x = self.find_father(x)
        y = self.find_father(y)
        if x == y:
            return False
        if x<y:
            x,y=y,x

        self.fathers[x] = y       
        return True 
    def is_same_father(self,x,y):
        return self.find_father(x)==self.find_father(y)
        
class Solution:
    def trulyMostPopular(self, names: List[str], synonyms: List[str]) -> List[str]:
        # print(names[0].split('('))
        frq = {}
        for name in names:
            a = name.split('(')
            b = a[1].split(')')
            frq[a[0]]=int(b[0])
        hashed = sorted(frq.keys())
        n = len(hashed)
        ans =  defaultdict(int)
        uf = UnionFind(n)
        for s in synonyms:
            ss = s.split(',')
            a = ss[0].split('(')[1]
            b = ss[1].split(')')[0]
            x = bisect_left(hashed,a)
            y = bisect_left(hashed,b)
            
            if x<n and y <n:
                uf.union(x,y)
        for a,b in frq.items():
            f = uf.find_father(bisect_left(hashed,a))
            ans[f] += b 
        return [f'{hashed[a]}({b})' for a,b in ans.items()]

基于字典的并查集

class UnionFind:
    def __init__(self,eles):
        self.fathers = {}
        f = self.fathers
        for e in eles:
            f[e] = e
        
    def find_father(self,x):
        f = self.fathers
        f.setdefault(x,x)
        return self._zip_find_father(x)    
    def _zip_find_father(self,x):
        fathers = self.fathers
        if fathers[x] != x:
            fathers[x] = self._zip_find_father(fathers[x])
        return fathers[x]                      
    def union(self,x,y):
        f = self.fathers
        f.setdefault(x,x)
        f.setdefault(y,y)
        x = self.find_father(x)
        y = self.find_father(y)
        if x == y:
            return False
        if x<y:
            x,y=y,x

        self.fathers[x] = y       
        return True 
    def is_same_father(self,x,y):
        return self.find_father(x)==self.find_father(y)
        
class Solution:
    def trulyMostPopular(self, names: List[str], synonyms: List[str]) -> List[str]: 
        # 频率入字典  
        frq = {}
        for name in names:
            a = name.split('(')
            b = a[1].split(')')
            frq[a[0]]=int(b[0])

        # 构建并查集
        uf = UnionFind(frq.keys())
        for s in synonyms:
            a,b = s[1:-1].split(',') 
            uf.union(a,b)  
            
        # 构建答案
        ans =  defaultdict(int)
        for a,b in frq.items():
            f = uf.find_father(a)
            ans[f] += b 
        return [f'{a}({b})' for a,b in ans.items()]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值