螺旋矩阵

标签: 数组 矩阵 模拟

难度: Medium

给你一个 mn 列的矩阵 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]

 

提示:

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

Submission

运行时间: 36 ms

内存: 14.8 MB

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if len(matrix) == 0:
            return []

        l = 0
        u = 0
        r = len(matrix[0])-1
        d = len(matrix)-1
        ans = []
        while True:
            for i in range(l, r+1):
                ans.append(matrix[u][i])
            u += 1
            if u > d:
                break
            for i in range(u, d+1):
                ans.append(matrix[i][r])
            r -= 1
            if l > r:
                break
            for i in range(r, l-1, -1):
                ans.append(matrix[d][i])
            d -= 1
            if u > d:
                break
            for i in range(d, u-1, -1):
                ans.append(matrix[i][l])
            l += 1
            if l > r:
                break
        return ans

Explain

这个题解采用了螺旋遍历矩阵的方法。初始化矩阵的上下左右四个边界,然后按照右、下、左、上的顺序依次遍历并收缩边界,直到遍历完整个矩阵。具体做法是:先从左到右遍历上边界,然后上边界下移;再从上到下遍历右边界,然后右边界左移;接着从右到左遍历下边界,然后下边界上移;最后从下到上遍历左边界,然后左边界右移。如此循环直至越过边界,遍历结束。

时间复杂度: O(m*n)

空间复杂度: O(m*n)

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if len(matrix) == 0:
            return []

        l = 0  # 左边界
        u = 0  # 上边界
        r = len(matrix[0])-1  # 右边界
        d = len(matrix)-1     # 下边界
        ans = []
        while True:
            # 遍历上边界,左到右
            for i in range(l, r+1):
                ans.append(matrix[u][i])
            u += 1  # 上边界下移
            if u > d:  # 遍历完成
                break
            
            # 遍历右边界,上到下
            for i in range(u, d+1):
                ans.append(matrix[i][r])
            r -= 1  # 右边界左移
            if l > r:  # 遍历完成
                break
            
            # 遍历下边界,右到左
            for i in range(r, l-1, -1):
                ans.append(matrix[d][i])
            d -= 1  # 下边界上移
            if u > d:  # 遍历完成
                break
            
            # 遍历左边界,下到上
            for i in range(d, u-1, -1):
                ans.append(matrix[i][l]) 
            l += 1  # 左边界右移
            if l > r:  # 遍历完成
                break
        return ans

Explore

在代码中,每次完成一个方向的遍历后,相应的边界会进行调整(例如上边界在遍历完后会下移,右边界在遍历完后会左移等)。这种调整确保了下一次遍历不会重复访问已遍历过的元素,并且边界的调整也作为循环停止的条件之一,当新的边界越过对面的边界时,循环会停止。这样,每个方向的遍历都只处理当前有效的区域,不会影响到下一次遍历。

在单行或单列的矩阵情况下,螺旋遍历的边界调整会迅速导致循环的结束。例如,对于单行矩阵,首次遍历右边界(即整行)后,上边界下移会立即超过下边界,触发循环结束条件。对于单列矩阵,首次遍历下边界(即整列)后,右边界左移会立即超过左边界,同样触发循环结束。这意味着在这些特殊情况下,部分遍历方向可能根本不会执行。

由于边界在每次遍历后都进行了适当的调整,例如上边界遍历完后即下移,这样的调整避免了下一轮遍历时重复访问已经遍历过的元素。每次边界调整后的检查条件(比如 'if u > d' 或 'if l > r')确保了一旦新的边界越过了对应的对面边界,相关方向的遍历便会停止,从而阻止了重复访问。

循环的停止条件是通过边界的相对位置来设计的。每次遍历一个方向结束时,都会对该方向的边界进行调整,然后检查是否新的边界已经越过了相对的边界(例如上边界是否已越过下边界,或左边界是否已越过右边界)。这些检查作为循环的停止条件,确保了遍历过程不会超出矩阵边界或重复访问元素。每个循环在进入之前都进行这样的条件判断,从而保持遍历的正确性和安全性。