- 题目描述
-
给你一个大小为 m x n 的整数矩阵 grid ,表示一个网格。另给你三个整数 row、col 和 color 。网格中的每个值表示该位置处的网格块的颜色。
当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一 连通分量 。
连通分量的边界 是指连通分量中的所有与不在分量中的网格块相邻(四个方向上)的所有网格块,或者在网格的边界上(第一行/列或最后一行/列)的所有网格块。
请你使用指定颜色 color 为所有包含网格块 grid[row][col] 的 连通分量的边界 进行着色,并返回最终的网格 grid 。 - 示例:
-
输入:grid = [[1,1],[1,2]], row = 0, col = 0, color = 3
输出:[[3,3],[3,2]]
输入:grid = [[1,2,2],[2,3,2]], row = 0, col = 1, color = 3
输出:[[1,3,3],[2,3,3]]
输入:grid = [[1,1,1],[1,1,1],[1,1,1]], row = 1, col = 1, color = 2
输出:[[2,2,2],[2,1,2],[2,2,2]] - 解析:这是一个看上去很复杂,实际上很简单,代码写起来很复杂的题目(哈哈哈,经典说了等于没说),说他看看上去很复杂是因为涉及到连通分量的边界问题,一个是处于连通分量中心(四个方向上均为同样的连通分量),一个是处于数组边界,所以不是几行代码就能搞定的,说他实际上很简单,是因为这个题目就考了一个深度优先遍历(当然,广度优先遍历也行),说他代码写起来很复杂,是因为这个题目有很多优化的空间,本例中我用了两个嵌套for循环来完成连通分量和其边界赋值,就很Low。
- 代码如下
class Solution:
def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
"""
使用指定颜色 color 为所有包含网格块 grid[row][col] 的 连通分量的边界 进行着色,并返回最终的网格 grid
>>>self.colorBorder([[1,1],[1,2]], 0, 0, 3)
>>>[[3,3],[3,2]]
"""
start = grid[row][col]
start_list = []
#深度优先遍历找到所有连通分量,并设置为0,因为color的取值范围是大于1的
def dfs(grid, row, col):
if grid[row][col] != start:
return
grid[row][col] = 0
for row1, col1 in [(row, col-1), (row, col+1), (row-1, col),(row+1, col)]:
if 0<=row1<len(grid) and 0<=col1<len(grid[0]):
dfs(grid, row1, col1)
dfs(grid, row, col)
#找到非连通分量边界的连通分量,保存索引
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 0:
if 0<i<len(grid)-1 and 0<j<len(grid[0])-1:
if self.helpFunc(grid, i, j):
start_list.append((i, j))
#为连通分量和连通分量边界分别赋值
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 0:
if (i, j) in start_list:
grid[i][j] = start
else:
grid[i][j] = color
return grid
def helpFunc(self, grid, i , j):
"""
一个help function,判断一个点的四个方向上的四个点是否全为0
>>>self.helpFunc([[0, 0 ,0], [0, 0 ,0], [0, 0 ,0]], 1, 1)
>>>True
"""
for ni, nj in [(i, j-1), (i, j+1), (i-1, j),(i+1, j)]:
if grid[ni][nj] != 0:
return False
return True
这里提供两个优化思路,代码我就不写了。
- 优化的重点就是两个嵌套for循环那里,优化思路就是把两个嵌套for循环缩减为一个嵌套for循环,这里有两种方式,第一种是在第一层嵌套for循环里面就完成赋值操作,这需要重写一下help function,在主方法里面进行赋值的时候记录所有值为0的坐标,将这个坐标数组作为参数传入help function,比如叫help_list:,这样就可以即便当前值改变了,也不影响后续的非连通分量边界分量的判断,这样help function的判断语句就变成了
if grid[ni][nj] != 0 and (i, j) not in help_list
- 第二种优化思路是在深度优先遍历的时候除了对原数组进行操作外,同时记录下所有连通分量的坐标位置,比如叫conn_list,然后对索引进行遍历赋值,这样的效率会更高,同样的这里也需要重写help_function,需要当前位置四个方向的所有坐标均在conn_list中,否则返回False,这种优化思路明显更好。测试时间从48ms变成了24ms。