54. 螺旋矩阵

54. 螺旋矩阵

✨核心逻辑

本题采用 模拟边界收缩(按层遍历) 的策略:

  1. 定义边界:维护四个变量 top(上边界)、bottom(下边界)、left(左边界)、right(右边界),分别代表当前未遍历矩阵区域的上下左右边缘。
  2. 顺时针遍历:在 top <= bottomleft <= right 的前提下,逐步按顺时针方向收缩边界:
    • 从左到右遍历上边界,遍历完后 top++(上边界向下收缩一行)。
    • 从上到下遍历右边界,遍历完后 right--(右边界向左收缩一列)。
    • 如果此时 top <= bottom,则从右到左遍历下边界,遍历完后 bottom--(下边界向上收缩一行)。
    • 如果此时 left <= right,则从下到上遍历左边界,遍历完后 left++(左边界向右收缩一列)。
  3. 循环终止:当四个边界交错(top > bottomleft > right)时,说明所有元素都已遍历完毕,循环结束。

🔥代码实现(含详细变量注释)

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        // res:用于记录最终按螺旋顺序输出的元素列表
        List<Integer> res = new ArrayList<>();
        
        // 边界情况:如果矩阵为空,直接返回空列表
        if (matrix.length == 0) {
            return res;
        }

        // top:初始化当前未遍历区域的上边界索引
        int top = 0;
        // bottom:初始化当前未遍历区域的下边界索引(矩阵总行数 - 1)
        int bottom = matrix.length - 1;
        // left:初始化当前未遍历区域的左边界索引
        int left = 0;
        // right:初始化当前未遍历区域的右边界索引(矩阵总列数 - 1)
        int right = matrix[0].length - 1;
        
        // 当上边界 <= 下边界,且左边界 <= 右边界时,说明还有未遍历的矩形区域,继续循环
        while (top <= bottom && left <= right) {
            // 第一步:从左到右遍历上边界
            for (int i = left; i <= right; i++) {
                res.add(matrix[top][i]);
            }
            // 上边界完成遍历,向下收缩一行
            top++;
            
            // 第二步:从上到下遍历右边界
            for (int i = top; i <= bottom; i++) {
                res.add(matrix[i][right]);
            }
            // 右边界完成遍历,向左收缩一列
            right--;
            
            // 第三步:如果此时上边界依然不大于下边界,说明还有底部行未遍历
            if (top <= bottom) {
                // 从右到左遍历下边界
                for (int i = right; i >= left; i--) {
                    res.add(matrix[bottom][i]);
                }
                // 下边界完成遍历,向上收缩一行
                bottom--;
            }
            
            // 第四步:如果此时左边界依然不大于右边界,说明还有左侧列未遍历
            if (left <= right) {
                // 从下到上遍历左边界
                for (int i = bottom; i >= top; i--) {
                    res.add(matrix[i][left]);
                }
                // 左边界完成遍历,向右收缩一列
                left++;
            }
        }
        // 返回最终按顺时针螺旋顺序收集的列表
        return res;
    }
}


  • ⏱️复杂度分析
    • 时间复杂度:O(m * n),其中 m 和 n 分别是矩阵的行数和列数。我们需要将矩阵中的每一个元素访问且仅访问一次,因此总操作次数与矩阵元素总数成正比。

    • 空间复杂度:O(1)(不考虑输出数组占用的空间)。我们只使用了 top、bottom、left、right 以及循环变量 i 等常数个额外的变量来进行边界控制

🔍总结一下:

一定要注意当走完左右方向以及上下方向的时候,后面两个循环要加if条件判断,否则会重复加入之前的路径元素

eg:

image-TghU.png