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

日报

  • 今天的题都比较朴素,并查集的基础应用。

题目

一、 1559. 二维网格图中探测环

链接: 1559. 二维网格图中探测环

1. 题目描述

在这里插入图片描述

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
        self.fathers[x] = y       
        return True 
class Solution:
    def containsCycle(self, grid: List[List[str]]) -> bool:
        m,n = len(grid),len(grid[0])
        uf = UnionFind(m*n)
        for i in range(m):
            for j in range(n):
                if i > 0:
                    if grid[i][j] == grid[i-1][j] and not uf.union(i*n+j,(i-1)*n+j):
                        return True
                if j > 0:
                    if grid[i][j] == grid[i][j-1] and not uf.union(i*n+j,i*n+j-1):
                        return True
        return False

在这里插入图片描述

二、 1391. 检查网格中是否存在有效路径

链接: 1391. 检查网格中是否存在有效路径

1. 题目描述

在这里插入图片描述

2. 思路分析

用并查集处理所有网格,最后检查起始点和结束点是否连通即可(祖宗相同)。

  • 这题特殊之处就是要全部特判相邻网格是否连通,v=grid[i][j]:
    • v==1时:它只能左右移动,且向左移动时,左边只能连接1、4、6;向右移动时,右边只能连接1、3、5。
    • v==其它时,均需特判。
    • 为了代码简洁,我们给1-6编号为0-5,用列表储存这6中情况分别对应的方向和方向上能连接的网格值。
    • 然后就是遍历所有网格并且让他们移动,判断移动后的网格符合条件就合并家族即可。
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
        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 hasValidPath(self, grid: List[List[int]]) -> bool:
        m,n = len(grid),len(grid[0])
        uf = UnionFind(m*n)
        def in_bound(x,y):
            return 0<=x<m and 0<=y<n
        def hashed(x,y):
            return x*n+y
        left = {1,4,6}
        right = {1,3,5}
        top = {2,3,4}
        bottom = {2,5,6}
        dirs = [  # 6个方块分别能走的方向
            [(0,1),(0,-1)],  # 右左
            [(1,0),(-1,0)],  # 下上
            [(0,-1),(1,0)],  # 左下
            [(0,1),(1,0)],   # 右下
            [(-1,0),(0,-1)], # 上左
            [(0,1),(-1,0)],  # 右上
        ]
        accepts = [  # 6个方块按方向走后,能连通的合法块
            [right,left],
            [bottom,top],
            [left,bottom],
            [right,bottom],
            [top,left],
            [right,top],
        ]
        for i in range(m):
            for j in range(n):
                k = grid[i][j] - 1  # 用来索引这个块的属性
                for z in range(2):  # 走他能走的两个方向
                    x,y = i+dirs[k][z][0],j+dirs[k][z][1]
                    accept = accepts[k][z]
                    if in_bound(x,y) and grid[x][y] in accept:
                        uf.union(hashed(i,j),hashed(x,y))

        return uf.is_same_father(hashed(0,0),hashed(m-1,n-1))

在这里插入图片描述

三、 1202. 交换字符串中的元素

链接: 1202. 交换字符串中的元素

1. 题目描述

在这里插入图片描述

2. 思路分析
  • 我们用并查集把可以互相交换的字符合并为家族。
  • 显然同一家族中的字符可以任意摆放。
  • 那么我们对每个家族内部排序,然后按顺序填回他们家族的位置即可。
  • 为了Python方便比较大小和转换,我先把所有字母变成ASCII码,最后拼接时再转回来。
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
        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 smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
        ss = [ord(c) for c in s]
        n = len(ss)
        uf = UnionFind(n)
        for a,b in pairs:
            uf.union(a,b)
        familys = defaultdict(list)
        for i in range(n):
            familys[uf.find_father(i)].append(i)
        
        ans = [0]*n
        for ps in familys.values():
            ps2 = sorted(ps,key=lambda x:ss[x])            
            # print (ps,ps2)
            for i in range(len(ps)):
                ans[ps[i]] = ss[ps2[i]] 
        
        return ''.join(chr(c) for c in ans)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值