【并查集】leetcode1034.边界着色

题目:
给你一个大小为 m x n 的整数矩阵 grid ,表示一个网格。另给你三个整数 row、col 和 color 。网格中的每个值表示该位置处的网格块的颜色。

  • 当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一 连通分量 。
  • 连通分量的边界 是指连通分量中的所有与不在分量中的网格块相邻(四个方向上)的所有网格块,或者在网格的边界上(第一行/列或最后一行/列)的所有网格块。

请你使用指定颜色 color 为所有包含网格块 grid[row][col] 的 连通分量的边界 进行着色,并返回最终的网格 grid 。
【并查集】leetcode1034.边界着色

解答:

方法一:并查集

1.确定跟grid[row][col]颜色相同的连通块;(体现在 并查集中根节点相同)
2.对连通分量的色块进行上色,上色有两种情况:(1)该色块在矩阵边界上;(2)该色块是连通分量边界,即该色块上下左右相邻色块至少有一个不属于(row, col)的连通分量。

class UF:
    def __init__(self, M):
        self.parent = {}
        # 初始化 parent 
        for i in range(M):
            self.parent[i] = i
    
    #判断x所属集合
    def find(self, x):
        while x!=self.parent[x]:
            x=self.parent[x]
        return x
    
    #合并p和q所在的集合 
    def union(self, p, q):
        if self.connected(p, q): 
            return
        proot = self.find(p)
        qroot = self.find(q)
        self.parent[qroot] = proot

        
    #判断两元素是否属于同一集合     
    def connected(self, p, q):
        return self.find(p) == self.find(q)



class Solution:
    def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
        m=len(grid)
        n=len(grid[0])
        uf=UF(m*n)
        
        #颜色相同且相邻,则对其进行合并
        for i in range(m):
            for j in range(n):
                #上
                if i>0 and grid[i-1][j]==grid[i][j]:
                    uf.union((i-1)*n+j,i*n+j)
                #左
                if j>0 and grid[i][j-1]==grid[i][j]:
                    uf.union(i*n+j-1,i*n+j)
      
        for i in range(m):
            for j in range(n):
                #是否跟grid[row][col]属于同一连通分量
                target=row*n+col
                if uf.connected(i*n+j,target):
                    #是不是位于 矩阵边界
                    if i==0 or i==m-1 or j==0 or j==n-1:
                        grid[i][j]=color
                        continue
                 
                    #是不是位于 连通分量边界,看【上下左右】是不是 不属于该连通分量
                    up=(i-1)*n+j
                    down=(i+1)*n+j
                    left=i*n+j-1
                    right=i*n+j+1
                    if (not uf.connected(up,target))  or (not uf.connected(down,target)) or (not uf.connected(left,target)) or (not uf.connected(right,target)):
                        grid[i][j]=color
        return grid

方法二:BFS
同一「连通分量」的「非边界」格子满足:当前格子的四个方向均存在相邻格子,且当前格子与四个相邻格子颜色一致。

  • 构造res矩阵作为答案,并将其元素初始化为0(若BFS结束,元素依旧为0,则其未被处理)
  • 将(row,col)入队,每次从队列中取出元素,进行四个方位的拓展。拓展时,拓展格子必须与(row,col)位置的元素值相等。
  • 记录当前出队元素是否为边界格子,若为边界格子则对其进行上色。
  • 结束后,遍历res矩阵,恢复未处理元素的原始色。若res[i][j]=0,则令res[i][j]=grid[i][j]

class Solution:
    def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
        #BFS
        m=len(grid)
        n=len(grid[0])
        #res:重判矩阵(通过判断元素是否为0来得知:是否被处理)
        res=[[0]*n for _ in range(m)]
        #dirs:记录方向,分别代表上下左右
        dirs=[(-1,0),(1,0),(0,-1),(0,1)]
        q=collections.deque()
        q.append([row,col])
        while q:
            #print(q)
            curx,cury=q.popleft()
            count=0
            for d in dirs:
                nx=curx+d[0]
                ny=cury+d[1]
                #print(nx,ny)
                if nx<0 or nx>=m or ny<0 or ny>=n:
                    continue
                if grid[nx][ny]!=grid[curx][cury]:
                    continue
                else:
                    count+=1
                #若当前元素已被处理过
                if res[nx][ny]!=0:
                    continue
                q.append([nx,ny])
            #print(count)
            #若当前元素(curx,cury)四个方位皆存在,且与其颜色相同,则当前元素为连通分量的中间元素
            if count==4:
                #恢复原始色
                res[curx][cury]=grid[curx][cury]
            else:
                res[curx][cury]=color
            #print(res)

        #恢复未处理元素的原始色
        for i in range(m):
            for j in range(n):
                if res[i][j]==0:
                    res[i][j]=grid[i][j]
        
        return res

方法三:DFS

上一篇:bootstrap-3-自定义栅格系统


下一篇:大厂算法面试之leetcode精讲6.深度优先&广度优先