项目地址:Python_test_3
前言
今天集中攻克了三道矩阵类高频题,分别是:
- 螺旋矩阵(按层模拟,方向控制)
- 矩阵旋转(原地旋转,两步法)
- 迷宫寻路(DFS + 回溯 / 迭代栈 + parent 字典)
其中迷宫寻路最考验细节,下面逐一总结。
一、螺旋矩阵(按层模拟)
核心思路
用四个变量top, bottom, left, right表示当前层的边界,每次按顺时针方向遍历四条边,然后收缩边界。
标准模板
def spiral_order(matrix): if not matrix or not matrix[0]: return [] m, n = len(matrix), len(matrix[0]) top, bottom, left, right = 0, m-1, 0, n-1 res = [] while top <= bottom and left <= right: # 上边:从左到右 for j in range(left, right+1): res.append(matrix[top][j]) top += 1 # 右边:从上到下 for i in range(top, bottom+1): res.append(matrix[i][right]) right -= 1 # 下边:从右到左(需要检查 top <= bottom) if top <= bottom: for j in range(right, left-1, -1): res.append(matrix[bottom][j]) bottom -= 1 # 左边:从下到上(需要检查 left <= right) if left <= right: for i in range(bottom, top-1, -1): res.append(matrix[i][left]) left += 1 return res易错点
- 单行或单列:遍历下边和左边前必须加
if判断,否则会重复遍历。 - 边界更新顺序:每遍历完一边立即更新边界,保证下一次遍历的范围正确。
二、矩阵旋转(原地旋转)
核心思路
两步法:先上下翻转,再沿主对角线对称交换。
标准模板(n×n 方阵)
def rotate(matrix): n = len(matrix) # 1. 上下翻转 for i in range(n // 2): matrix[i], matrix[n-1-i] = matrix[n-1-i], matrix[i] # 2. 主对角线对称交换(只遍历上三角) for i in range(n): for j in range(i+1, n): matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]易错点
- 对角线交换范围:必须是
j > i(上三角),不能遍历下三角,否则会重复交换导致还原。 - 上下翻转的循环次数:
n // 2,奇数时中间一行不动。 - 原地操作:不需要额外矩阵,但需要临时变量(Python 元组交换自动处理)。
变体
- 逆时针旋转:先左右翻转,再主对角线对称;或先上下翻转,再副对角线对称。
三、迷宫寻路(DFS + parent 字典)
题目描述
给定 m×n 网格,0 可通行,1 障碍,从 (0,0) 到 (m-1,n-1),只能向右或向下,返回任意一条路径。
迭代 DFS 标准模板
def find_path(grid): if not grid or not grid[0]: return [] m, n = len(grid), len(grid[0]) # 起点或终点是障碍,直接返回 if grid[0][0] == 1 or grid[m-1][n-1] == 1: return [] stack = [(0, 0)] parent = {(0, 0): None} # 记录每个格子的前驱 found = False while stack: x, y = stack.pop() if x == m-1 and y == n-1: found = True break # 只向右和向下 for dx, dy in [(0, 1), (1, 0)]: nx, ny = x + dx, y + dy # 注意:检查新格子是否可通行,不是当前格子 if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 0 and (nx, ny) not in parent: parent[(nx, ny)] = (x, y) stack.append((nx, ny)) if not found: return [] # 回溯路径 path = [] cur = (m-1, n-1) while cur is not None: path.append(cur) cur = parent[cur] path.reverse() return path⚠️ 细节陷阱(最容易摸错的地方)
陷阱1:起点/终点的障碍检查
# ❌ 错误:用 and if grid[0][0] == 1 and grid[m-1][n-1] == 1: return [] # ✅ 正确:用 or,只要有一个是障碍就返回 if grid[0][0] == 1 or grid[m-1][n-1] == 1: return []原因:起点或终点任一为障碍,都不可能到达,必须提前返回。
陷阱2:邻居合法性检查中的grid判断
# ❌ 错误:检查当前格子 if ... and grid[x][y] == 0 and ... # ✅ 正确:检查新格子 if ... and grid[nx][ny] == 0 and ...原因:当前格子(x,y)既然在栈中,说明它一定是可通行的(已通过前面的检查)。我们需要判断的是下一步要去的格子是否可通行。
陷阱3:parent字典的初始化
# 正确写法 parent = {(0, 0): None}原因:起点没有前驱,设为None。回溯时作为终止条件。如果漏掉初始化,回溯到起点时会报 KeyError。
陷阱4:not in parent的作用
if ... and (nx, ny) not in parent:作用:防止重复访问同一个格子。因为只能向右向下,理论上不会走回头路,但为了避免环形路径或重复入栈,加上这个判断更安全。同时,它也起到了visited的作用。
陷阱5:路径回溯的方向
# 从终点开始 cur = (m-1, n-1) while cur is not None: path.append(cur) cur = parent[cur] # 跳到前一个格子 path.reverse() # 反转得到正确顺序注意:parent记录的是“从哪来”,所以回溯时是从终点倒着走到起点,最后必须反转。
陷阱6:栈的弹出顺序影响路径
- 使用
stack.pop()(后进先出)是 DFS,找到的路径不一定最短。 - 如果要求最短路径,应使用 BFS(队列
collections.deque)。
四、总结
题目 | 核心技巧 | 易错点 |
|---|---|---|
螺旋矩阵 | 四边界变量 + 方向循环 | 单行/单列时的边界判断 |
矩阵旋转 | 上下翻转 + 对角线交换 | 对角线遍历范围(上三角) |
迷宫寻路 | 迭代 DFS + parent 字典 | 起点/终点检查、新格子判断、parent 初始化、回溯反转 |
矩阵类题型的关键在于边界条件的全覆盖和细节的严谨性。建议每道题至少手写三遍,直到闭眼能写出无 bug 的代码。
五、练习建议
- 螺旋矩阵 II(按螺旋顺序填充矩阵)—— 巩固方向控制。
- 岛屿数量(DFS/BFS 连通分量)—— 巩固 DFS 遍历。
- 单词搜索(矩阵中找单词,回溯)—— 巩固回溯 + visited 管理。
祝你考试顺利,拿下 200 分!🚀