螺旋遍历二维数组

标签: 数组 矩阵 模拟

难度: Easy

给定一个二维数组 array,请返回「螺旋遍历」该数组的结果。

螺旋遍历:从左上角开始,按照 向右向下向左向上 的顺序 依次 提取元素,然后再进入内部一层重复相同的步骤,直到提取完所有元素。

示例 1:

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

示例 2:

输入:array  = [[1,2,3,4],[12,13,14,5],[11,16,15,6],[10,9,8,7]]
输出:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

限制:

  • 0 <= array.length <= 100
  • 0 <= array[i].length <= 100

注意:本题与主站 54 题相同:https://leetcode-cn.com/problems/spiral-matrix/

Submission

运行时间: 40 ms

内存: 15.3 MB

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if len(matrix) == 0:
            return []
        res = []
        l, r, t, b = 0, len(matrix[0])-1, 0, len(matrix)-1
        while True:
            for i in range(l, r+1):
                res.append(matrix[t][i])
            t += 1
            if t > b:
                break
            for i in range(t, b+1):
                res.append(matrix[i][r])
            r -= 1
            if l > r:
                break
            for i in range(r, l-1, -1):
                res.append(matrix[b][i])
            b -= 1
            if t > b:
                break
            for i in range(b, t-1, -1):
                res.append(matrix[i][l])
            l += 1
            if l > r:
                break
        return res

Explain

该题解的主要思路是使用四个指针来标识二维数组的边界:左边界l,右边界r,上边界t,下边界b。初始化时,左边界和上边界设为0,右边界和下边界分别设为列数减一和行数减一。按照题目要求的螺旋顺序,从左到右遍历上边界行,然后下移上边界;从上到下遍历右边界列,然后左移右边界;从右到左遍历下边界行,然后上移下边界;从下到上遍历左边界列,然后右移左边界。每次遍历结束后,检查边界条件以决定是否继续遍历。如果某个方向的新边界越界,则结束螺旋遍历。

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

空间复杂度: O(1)

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if len(matrix) == 0:
            return []
        res = []
        l, r, t, b = 0, len(matrix[0])-1, 0, len(matrix)-1
        while True:
            for i in range(l, r+1):  # 从左至右遍历上边界
                res.append(matrix[t][i])
            t += 1  # 上边界下移
            if t > b:  # 检查新的上边界是否有效
                break
            for i in range(t, b+1):  # 从上至下遍历右边界
                res.append(matrix[i][r])
            r -= 1  # 右边界左移
            if l > r:  # 检查新的右边界是否有效
                break
            for i in range(r, l-1, -1):  # 从右至左遍历下边界
                res.append(matrix[b][i])
            b -= 1  # 下边界上移
            if t > b:  # 检查新的下边界是否有效
                break
            for i in range(b, t-1, -1):  # 从下至上遍历左边界
                res.append(matrix[i][l])
            l += 1  # 左边界右移
            if l > r:  # 检查新的左边界是否有效
                break
        return res

Explore

在该螺旋遍历算法中,通过不断地调整四个边界(左、右、上、下)来确保不会重复访问元素。每完成一行或一列的遍历后,相应的边界会向内移动(例如,遍历完最上面一行后,上边界下移)。边界的调整保证了下一次遍历时,之前已遍历的行或列不会被再次访问。此外,通过在每次遍历后检查新的边界条件(如 'if t > b'),若新的边界无效,则停止遍历,避免了重复访问。

该螺旋遍历算法假设二维数组是规则的,即每一行的列数相同。如果二维数组是不规则的(某些行的列数不同),该算法可能无法正确运行,因为在遍历过程中可能会尝试访问不存在的索引,从而引发错误。针对不规则的二维数组,需要修改算法以检查每一行的实际列数,或者在实现前对数组进行规范化处理。

在螺旋遍历算法中,边界检查是必要的,因为它决定了遍历是否继续。在每个遍历步骤之后立即进行边界检查是有效的,因为它确保了即使数组大小变化,也不会导致访问越界。这种方法在逻辑上简单且直接,有助于维护代码的清晰性和正确性。尽管存在理论上的优化可能,如在循环开始前预计算条件,但在实际中这种优化可能带来的性能提升有限,而且会增加代码复杂度。

当二维数组为空时,该算法在开始时检查数组长度,并直接返回空列表,这是适当的处理方式。对于非常小的数组如1x1或1x2,该算法同样有效。算法通过边界检查来适应不同大小的数组,避免了越界访问,并能正确输出小数组的螺旋遍历结果。因此,不需要对这些特殊情况进行额外处理,算法已经能够妥善处理这些场景。