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

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

    • 日报
    • 题目
      • 一、 面试题 17.07. 婴儿名字
        • 1. 题目描述
        • 2. 思路分析
        • 3. 代码实现

日报

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

题目

一、 面试题 17.07. 婴儿名字

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

1. 题目描述

[英雄星球七月集训LeetCode解题日报] 第26日 并查集_第1张图片

2. 思路分析

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

  • 实测不离散化更快。
  • 基于字典的并查集要注意,findfather和union之前,把x,y都setdefault本身
    [英雄星球七月集训LeetCode解题日报] 第26日 并查集_第2张图片

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()]

你可能感兴趣的:(英雄星球七月集训,今天开刷leetcode,leetcode,算法,职场和发展)