☰
矩阵遍历算法与LeetCode刷题实战指南
2026/11/3 17:34:05 网站建设 项目流程

1. 矩阵遍历基础与LeetCode刷题指南

矩阵遍历是算法学习中最基础却至关重要的技能,就像建筑工人必须熟练掌握砌砖才能盖楼一样。我在ACM竞赛和硅谷大厂面试中深刻体会到,90%的二维矩阵类算法题都建立在四种基础遍历方法之上。本文将分享如何系统掌握这些技巧,并高效应用到LeetCode刷题中。

刚接触矩阵问题时,很多人会陷入"一看就会,一写就废"的困境。比如明明知道DFS可以解决岛屿问题,但实现时总是出现数组越界或死循环。这通常是因为对遍历的边界条件和访问顺序理解不够透彻。通过本文的图示分解和实战代码,你将建立起清晰的解题框架。

2. 矩阵遍历的四种核心模式

2.1 顺序遍历法

这是最直观的遍历方式,就像读书时从左到右、从上到下逐行阅读。以LeetCode 867(矩阵转置)为例:

def transpose(matrix): rows, cols = len(matrix), len(matrix[0]) res = [[0]*rows for _ in range(cols)] for i in range(rows): for j in range(cols): res[j][i] = matrix[i][j] # 行列坐标互换 return res

关键点在于:

  1. 外层循环控制行号,内层循环控制列号
  2. 转置操作本质是行列索引交换
  3. 新建矩阵的维度是原矩阵的逆(cols×rows)

注意:Python中不要用[[0]*rows]*cols初始化矩阵,这会导致行间引用问题

2.2 螺旋遍历法

类似蛇形填数,常用于LeetCode 54(螺旋矩阵)这类题目。核心是维护四个边界:

def spiralOrder(matrix): res = [] top, bottom = 0, len(matrix)-1 left, right = 0, len(matrix[0])-1 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 if top <= bottom: # 防止单行重复 # 从右到左 for j in range(right, left-1, -1): res.append(matrix[bottom][j]) bottom -= 1 if left <= right: # 防止单列重复 # 从下到上 for i in range(bottom, top-1, -1): res.append(matrix[i][left]) left += 1 return res

2.3 对角线遍历

LeetCode 498(对角线遍历)展示了这种特殊遍历方式。关键在于发现:

  • 奇数对角线方向为右上到左下
  • 偶数对角线方向为左下到右上
def findDiagonalOrder(matrix): if not matrix: return [] m, n = len(matrix), len(matrix[0]) res = [] for s in range(m + n - 1): if s % 2 == 0: # 偶数对角线 i = min(s, m-1) j = s - i while i >= 0 and j < n: res.append(matrix[i][j]) i -= 1 j += 1 else: # 奇数对角线 j = min(s, n-1) i = s - j while j >= 0 and i < m: res.append(matrix[i][j]) i += 1 j -= 1 return res

2.4 BFS/DFS遍历

图论算法在矩阵中的应用,典型题目如LeetCode 200(岛屿数量):

def numIslands(grid): count = 0 for i in range(len(grid)): for j in range(len(grid[0])): if grid[i][j] == '1': count += 1 self.dfs(grid, i, j) return count def dfs(grid, i, j): if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j]!='1': return grid[i][j] = '0' # 标记为已访问 dfs(grid, i+1, j) dfs(grid, i-1, j) dfs(grid, i, j+1) dfs(grid, i, j-1)

3. 矩阵遍历的六大经典问题

3.1 旋转图像(LeetCode 48)

解法一:转置+镜像

def rotate(matrix): n = len(matrix) # 转置 for i in range(n): for j in range(i+1, n): matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] # 水平翻转 for i in range(n): matrix[i] = matrix[i][::-1]

解法二:分层旋转(更符合题意)

def rotate(matrix): n = len(matrix) for layer in range(n//2): first = layer last = n - 1 - layer for i in range(first, last): offset = i - first # 保存上边 top = matrix[first][i] # 左到上 matrix[first][i] = matrix[last-offset][first] # 下到左 matrix[last-offset][first] = matrix[last][last-offset] # 右到下 matrix[last][last-offset] = matrix[i][last] # 上到右 matrix[i][last] = top

3.2 矩阵置零(LeetCode 73)

O(1)空间复杂度解法:

def setZeroes(matrix): m, n = len(matrix), len(matrix[0]) first_row_has_zero = any(matrix[0][j] == 0 for j in range(n)) first_col_has_zero = any(matrix[i][0] == 0 for i in range(m)) # 使用第一行和第一列作为标记 for i in range(1, m): for j in range(1, n): if matrix[i][j] == 0: matrix[i][0] = 0 matrix[0][j] = 0 # 根据标记置零 for i in range(1, m): for j in range(1, n): if matrix[i][0] == 0 or matrix[0][j] == 0: matrix[i][j] = 0 # 处理第一行和第一列 if first_row_has_zero: for j in range(n): matrix[0][j] = 0 if first_col_has_zero: for i in range(m): matrix[i][0] = 0

3.3 搜索二维矩阵(LeetCode 240)

Z字形搜索法:

def searchMatrix(matrix, target): if not matrix: return False m, n = len(matrix), len(matrix[0]) row, col = 0, n-1 # 从右上角开始 while row < m and col >= 0: if matrix[row][col] == target: return True elif matrix[row][col] < target: row += 1 # 排除当前行 else: col -= 1 # 排除当前列 return False

4. 矩阵遍历的优化技巧

4.1 方向数组的妙用

在DFS/BFS遍历中,使用方向数组可以简化代码:

# 四方向 directions = [(-1,0),(1,0),(0,-1),(0,1)] # 八方向 directions_8 = [(-1,-1),(-1,0),(-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)] def dfs(grid, i, j): grid[i][j] = '0' # 标记访问 for di, dj in directions: ni, nj = i+di, j+dj if 0<=ni<len(grid) and 0<=nj<len(grid[0]) and grid[ni][nj]=='1': dfs(grid, ni, nj)

4.2 虚拟边界技术

处理边界条件时,可以在矩阵外围添加虚拟边界:

def islandPerimeter(grid): m, n = len(grid), len(grid[0]) dummy_grid = [[0]*(n+2)] + [[0]+row+[0] for row in grid] + [[0]*(n+2)] perimeter = 0 for i in range(1, m+1): for j in range(1, n+1): if dummy_grid[i][j] == 1: perimeter += 4 - (dummy_grid[i-1][j] + dummy_grid[i+1][j] + dummy_grid[i][j-1] + dummy_grid[i][j+1]) return perimeter

4.3 记忆化遍历

对于需要重复计算的路径问题,使用记忆化存储中间结果:

def longestIncreasingPath(matrix): if not matrix: return 0 m, n = len(matrix), len(matrix[0]) memo = [[0]*n for _ in range(m)] max_len = 0 def dfs(i, j): if memo[i][j] != 0: return memo[i][j] max_depth = 1 for di, dj in directions: ni, nj = i+di, j+dj if 0<=ni<m and 0<=nj<n and matrix[ni][nj]>matrix[i][j]: max_depth = max(max_depth, 1 + dfs(ni, nj)) memo[i][j] = max_depth return max_depth for i in range(m): for j in range(n): max_len = max(max_len, dfs(i, j)) return max_len

5. 矩阵类题目刷题路线

5.1 新手必刷题单

  1. 基础遍历:566(重塑矩阵)、661(图片平滑器)
  2. 旋转镜像:48(旋转图像)、151(反转字符串里的单词)
  3. 搜索问题:74(搜索二维矩阵)、240(搜索二维矩阵II)
  4. 动态规划:64(最小路径和)、221(最大正方形)
  5. DFS/BFS:200(岛屿数量)、542(01矩阵)

5.2 进阶挑战题单

  1. 复杂遍历:329(矩阵中的最长递增路径)、407(接雨水II)
  2. 数学技巧:54(螺旋矩阵)、59(螺旋矩阵II)
  3. 综合应用:85(最大矩形)、212(单词搜索II)

5.3 大厂高频考题

  • 字节跳动:48(旋转图像)、200(岛屿数量)
  • 谷歌:54(螺旋矩阵)、329(最长递增路径)
  • 亚马逊:733(图像渲染)、994(腐烂的橘子)

6. 调试技巧与常见错误

6.1 矩阵遍历的三大陷阱

  1. 索引越界:始终检查i±1/j±1是否在[0, len-1]范围内
  2. 重复访问:DFS中忘记标记已访问会导致死循环
  3. 浅拷贝问题:Python中用new = matrix[:]只能浅拷贝一维列表

6.2 调试可视化技巧

打印矩阵的辅助函数:

def print_matrix(matrix): for row in matrix: print(' '.join(f'{num:3}' for num in row)) print('-'*20)

6.3 边界条件检查清单

  1. 空矩阵输入:[]或[[]]
  2. 单行/单列矩阵:[[1,2,3]]或[[1],[2],[3]]
  3. 极值测试:100×100的矩阵,元素全相同
  4. 特殊值:包含负数、零、大整数的情况

我在刷题过程中总结出一个有效方法:遇到矩阵问题时,先在纸上画出3×3的示例矩阵,手动模拟算法流程。这能帮助快速发现逻辑漏洞,比直接写代码调试效率高得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询