LeetCode热题100——54.螺旋矩阵

37 阅读2分钟

题目描述

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

 

示例:

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

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

解法

边界收缩法

/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function (matrix) {
    if (matrix.length === 0) return []
    const res = []
    let top = 0, bottom = matrix.length - 1, left = 0, right = matrix[0].length - 1
    while (top < bottom && left < right) {
        for (let i = left; i < right; i++) res.push(matrix[top][i])   // 上层
        for (let i = top; i < bottom; i++) res.push(matrix[i][right]) // 右层
        for (let i = right; i > left; i--) res.push(matrix[bottom][i])// 下层
        for (let i = bottom; i > top; i--) res.push(matrix[i][left])  // 左层
        right--
        top++
        bottom--
        left++  // 四个边界同时收缩,进入内层
    }
    if (top === bottom) // 剩下一行,从左到右依次添加
        for (let i = left; i <= right; i++) res.push(matrix[top][i])
    else if (left === right) // 剩下一列,从上到下依次添加
        for (let i = top; i <= bottom; i++) res.push(matrix[i][left])
    return res
};

image.png

很明显,如果每个方向遍历到前一个位置停下,这样当每次一个顺时针循环下来,上下左右的起始位置到刚好减一。这样方便我们遍历完一个方向后,找到下一个遍历方向的起点 我们定义每次遍历的方阵的四个边界为:

  • top 初始化为0
  • botttom 初始化为matrix.length-1 即矩阵的行数
  • left 初始化为0
  • right 初始化为matrix[0]-1 即矩阵的列数

创建res数组存放结果

然后我们右下左上这四个方向遍历一遍为一次"环"遍历,当构不成环(即只剩下一列/一行)时,我们结束这个环遍历,最后将剩下的一行/一列按顺时针方向添加进结果中

具体实现: 通过while循环来实现一直环遍历 ,结束的条件就是只剩一行/列top < bottom && left < right。 在while循环内部:

  • 从左到右遍历:for (let i = left; i < right; i++) res.push(matrix[top][i])
  • 从上到下遍历:for (let i = top; i < bottom; i++) res.push(matrix[i][right])
  • 从右到左遍历: for (let i = right; i > left; i--) res.push(matrix[bottom][i])
  • 从下到上遍历: for (let i = bottom; i > top; i--) res.push(matrix[i][left])
  • 一个环遍历后,将边界向内收缩 right-- 、 top++ 、 bottom-- 、 left++

当所有的环遍历结束后,添加上剩下的一行/列

  • 剩下一行(top===bottom)
    • for (let i = left; i <= right; i++) res.push(matrix[top][i])
    • 从左到右(因为是顺时针方向,且最后剩余部分构不成一个环,那么这个是这个层首次被访问,应该是从左到右)
  • 剩下一列(left===right)
    • for (let i = top; i <= bottom; i++) res.push(matrix[i][left])
    • 从上到下 (同样是该层首次被访问,从上到下)

最后返回res

时间、空间复杂度

时间复杂度:O(M×N)O(M \times N)

算法遍历矩阵中的每个元素恰好一次。

空间复杂度:O(1)O(1) (不计输出数组)

仅使用了 top, bottom, left, right 等常数额外的空间。

参考链接 leetcode.cn/problems/sp…