【力扣-54. 螺旋矩阵 ✨】Python笔记

6 阅读3分钟

【算法精讲】LeetCode 54. 螺旋矩阵:模拟遍历的艺术

摘要:本文详解 LeetCode 54 题“螺旋矩阵”,通过维护上下左右边界指针,按顺时针方向逐层遍历矩阵。每完成一圈收缩边界,直到所有元素被访问。时间 O(MN),空间 O(1)(不计输出),是模拟类题目的经典范式。


🧠 核心知识点:什么是“模拟法”?

在算法题中,“模拟法”指:

  • 严格按照题目描述的规则或过程一步步执行
  • 不需要复杂的数据结构或数学推导,重在逻辑严谨和边界控制。
  • 常用于矩阵遍历、路径搜索、状态机等问题。

对于二维矩阵的“螺旋遍历”,关键在于:

如何用变量控制当前遍历的方向和范围?

本题正是这一思想的绝佳实践 —— 我们用四个指针 top, bottom, left, right 来动态界定当前待遍历的“环形区域”。


🎯 题目引入:LeetCode 54. 螺旋矩阵

题目描述

给你一个 m x n 的矩阵 matrix,请按照 顺时针螺旋顺序,返回矩阵中的所有元素。

约束条件:

  • 矩阵可能为空,也可能为单行/单列。
  • 必须按“右→下→左→上”的顺序循环遍历,直到所有元素都被访问。

示例 1:

输入: matrix = [[1,2,3],
                [4,5,6],
                [7,8,9]]
输出: [1,2,3,6,9,8,7,4,5]

示例 2:

输入: matrix = [[1,2,3,4],
                [5,6,7,8],
                [9,10,11,12]]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

💡 解题思路详解

❗ 为什么不能简单用嵌套循环?

因为螺旋路径不是固定的矩形块,而是随着遍历不断“内缩”的环形结构。我们需要动态调整遍历范围。

✅ 正确做法:用四个边界指针 + 方向控制

🔍 关键洞察:像剥洋葱一样一层层遍历

我们可以这样做:

  1. 初始化四个边界指针

    • top = 0, bottom = m - 1
    • left = 0, right = n - 1
  2. 定义遍历方向顺序

    • 右 → 下 → 左 → 上 (循环)
  3. 每一圈分四步走

    • 从左到右遍历顶行 → top++
    • 从上到下遍历右列 → right--
    • 从右到左遍历底行(如果还有行)→ bottom--
    • 从下到上遍历左列(如果还有列)→ left++
  4. 终止条件:当 top > bottomleft > right 时停止。

⚠️ 注意:第三步和第四步需要判断是否仍有有效行/列,避免重复遍历!


💻 代码实现与逐行解析

from typing import List

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return []
        
        m, n = len(matrix), len(matrix[0])
        result = []
        
        top, bottom = 0, m - 1
        left, right = 0, n - 1
        
        while top <= bottom and left <= right:
            # 1. 从左到右遍历顶行
            for col in range(left, right + 1):
                result.append(matrix[top][col])
            top += 1
            
            # 2. 从上到下遍历右列
            for row in range(top, bottom + 1):
                result.append(matrix[row][right])
            right -= 1
            
            # 3. 从右到左遍历底行(需检查是否还有行)
            if top <= bottom:
                for col in range(right, left - 1, -1):
                    result.append(matrix[bottom][col])
                bottom -= 1
            
            # 4. 从下到上遍历左列(需检查是否还有列)
            if left <= right:
                for row in range(bottom, top - 1, -1):
                    result.append(matrix[row][left])
                left += 1
        
        return result

📊 复杂度分析

  • 空间复杂度: O(1)O(1)(不计输出数组)
    仅使用了常数个变量(top, bottom, left, right, result 是返回值,不算额外空间)。

✅ 若考虑输出数组,则空间为 O(MN)O(MN),但这是不可避免的,因为要返回所有元素。


⚠️ 易错点提醒

  1. 忘记判断第三步和第四步的有效性:可能导致重复添加元素或越界。
  2. 边界更新顺序错误:比如先更新 top 再遍历右列,会导致漏掉角落元素。
  3. 空矩阵未处理:虽然题目一般保证非空,但健壮性代码应包含此判断。

🔄 对比其他解法

方法时间复杂度空间复杂度是否易读
递归分层O(MN)O(min(M,N))较难
方向向量+visitedO(MN)O(MN)中等
本题解法O(MN)O(1)

✅ 本题解法是面试最推荐写法,逻辑清晰、效率高、易于调试!