13.矩阵遍历
矩阵遍历涉及使用不同技术(DFS、BFS等)遍历矩阵中的元素。
在处理涉及水平、垂直或对角线遍历二维网格或矩阵的问题时使用此模式。
本质:从某个点出发,向 上下左右/八个方向 扩散,搜索符合条件的区域
万能题解 四步走:
1.确定方向 :
最常用就是 上下左右 4个方向
2.判断坐标是否合法? 0 <= x < 行 && 0 <= y < 列
3. 标记已访问 :要么修改原矩阵(把走过的设为0)、要么用visited矩阵
4.选择搜索方式:
- 求连通块、面积、区域 -> 用 DFS
- 求最短路路径、层级扩散 -> 用 BFS
图像渲染(LeetCode#733)
题目描述
有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。你也被给予三个整数 sr , sc 和 color 。你应该从像素 image[sr][sc] 开始对图像进行上色 填充 。
为了完成 上色工作:
- 从初始像素开始,将其颜色改为
color。 - 对初始坐标的 上下左右四个方向上 相邻且与初始像素的原始颜色同色的像素点执行相同操作。
- 通过检查与初始像素的原始颜色相同的相邻像素并修改其颜色来继续 重复 此过程。
- 当 没有 其它原始颜色的相邻像素时 停止 操作。
- 最后返回经过上色渲染 修改 后的图像 。
示例 1:

输入:image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, color = 2
输出:[[2,2,2],[2,2,0],[2,0,1]]
解释:在图像的正中间,坐标 (sr,sc)=(1,1) (即红色像素),在路径上所有符合条件的像素点的颜色都被更改成相同的新颜色(即蓝色像素)。
注意,右下角的像素 没有 更改为2,因为它不是在上下左右四个方向上与初始点相连的像素点。
示例 2:
输入:image = [[0,0,0],[0,0,0]], sr = 0, sc = 0, color = 0
输出:[[0,0,0],[0,0,0]]
解释:初始像素已经用 0 着色,这与目标颜色相同。因此,不会对图像进行任何更改。
提示:
m == image.length
n == image[i].length
1 <= m, n <= 50
0 <= image[i][j], color < 216
0 <= sr < m
0 <= sc < n
题目求解
使用BFS解决
python
from collections import deque
class Solution:
def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
# 感觉和腐烂的橘子类似
m = len(image)
n = len(image[0])
if sr < 0 or sr >= m or sc < 0 or sc >= n:
return image
# (sr, sc) 点出的像素值:
init_color = image[sr][sc]
if init_color == color:
return image
indexes = [[-1, 0], [1, 0], [0, -1], [0, 1]]
queue = deque()
queue.append((sr, sc))
image[sr][sc] = color
# 使用BFS
while queue:
i, j = queue.popleft()
for x, y in indexes:
new_x = i + x
new_y = j + y
if 0 <= new_x < m and 0 <= new_y < n and image[new_x][new_y] == init_color:
image[new_x][new_y] = color
queue.append((new_x, new_y))
return image
使用DFS 解决:
python
class Solution:
def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
# 也可以使用DFS来解决
m, n = len(image), len(image[0])
currColor = image[sr][sc]
def dfs(x, y):
if image[x][y] == currColor:
image[x][y] = color
for new_x, new_y in [[x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]]:
if 0 <= new_x < m and 0 <= new_y < n:
dfs(new_x, new_y)
if currColor != color:
dfs(sr, sc)
return image
岛屿数量(LeetCode#200)
题目描述
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
['1','1','1','1','0'],
['1','1','0','1','0'],
['1','1','0','0','0'],
['0','0','0','0','0']
]
输出:1
示例 2:
输入:grid = [
['1','1','0','0','0'],
['1','1','0','0','0'],
['0','0','1','0','0'],
['0','0','0','1','1']
]
输出:3
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'
题目求解
- 遍历每个格子
- 遇到 1 就说明发现新岛屿
- 用 DFS 把整个岛屿变成 0(标记访问)
- 岛屿计数 +1
有个关键的问题:没注意到 人家存的是 字符!
python
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
m, n = len(grid), len(grid[0])
# 遍历每个格子
# 遇到1就说明发现新岛屿
# 用DFS把整个岛屿变成0
# 岛屿计数
def dfs(i, j):
if grid[i][j] != '1':
return
grid[i][j] = '0'
for x, y in [[i - 1, j], [i + 1, j], [i, j - 1], [i, j + 1]]:
if 0 <= x < m and 0 <= y < n:
dfs(x, y)
ans = 0
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
dfs(i, j)
ans += 1
return ans
被围绕区域(LeetCode#130)
题目描述
给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' 组成,捕获 所有 被围绕的区域:
连接:一个单元格与水平或垂直方向上相邻的单元格连接。
区域:连接所有 'O' 的单元格来形成一个区域。
围绕:如果一个区域中的所有 'O' 单元格都不在棋盘的边缘,则该区域被包围。这样的区域 完全 被 'X' 单元格包围。
通过 原地 将输入矩阵中的所有 'O' 替换为 'X' 来 捕获被围绕的区域。你不需要返回任何值。
示例 1:
输入:board = [['X','X','X','X'],['X','O','O','X'],['X','X','O','X'],['X','O','X','X']]
输出:[['X','X','X','X'],['X','X','X','X'],['X','X','X','X'],['X','O','X','X']]
解释:

在上图中,底部的区域没有被捕获,因为它在 board 的边缘并且不能被围绕。
示例 2:
输入:board = [['X']]
输出:[['X']]
提示:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j] 为 'X' 或 'O'
题目求解
感觉做了很多DFS和BFS的题,再遇上新的还是有些懵,思路被限制了感觉。
总结一下所有题:
- 从点扩散 (岛屿、染色):从某一点 向 上下左右 扩散
- 从边界向内扩散 (围绕的区域、水流): 不找被包围的,找 没有被包围的!(被包围的没有破绽,但是没有被包围的 是连着边界的)
- 从起点到终点(迷宫、最短路径)
解题步骤:
- 只遍历四条边界上的所有格子
- 遇到边界的O,就启动DFS或者BFS
- 把所有连通到边界的O标记成临时符号,比如 #
- 遍历整个矩阵 (没被包围的变成 O,包围的O变成X)
代码实现:
python
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
m, n = len(board), len(board[0])
def dfs(i, j):
board[i][j] = 'A'
for x, y in [[i - 1, j], [i + 1, j], [i, j - 1], [i, j + 1]]:
if 0 <= x < m and 0 <= y < n and board[x][y] == 'O':
dfs(x, y)
for i in range(m):
for j in range(n):
if i == 0 or i == m - 1 or j == 0 or j == n-1:
if board[i][j] == 'O':
dfs(i, j)
for i in range(m):
for j in range(n):
if board[i][j] == 'O':
board[i][j] = 'X'
if board[i][j] == 'A':
board[i][j] = 'O'