题目:
给你一个大小为 m x n 的整数矩阵 grid ,表示一个网格。另给你三个整数 row、col 和 color 。网格中的每个值表示该位置处的网格块的颜色。
- 当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一 连通分量 。
- 连通分量的边界 是指连通分量中的所有与不在分量中的网格块相邻(四个方向上)的所有网格块,或者在网格的边界上(第一行/列或最后一行/列)的所有网格块。
请你使用指定颜色 color 为所有包含网格块 grid[row][col] 的 连通分量的边界 进行着色,并返回最终的网格 grid 。
解答:
方法一:并查集
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