Stefan Pochmann 的上帝之手(2)旋转打印矩阵

螺旋矩阵

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例 1:

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

示例 2:

输入:
[
  [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 (18行)

链接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode-solution/
模拟螺旋矩阵的路径,初始位置是矩阵的左上角,初始方向是向右,当路径超出界限或者进入之前访问过的位置时,则顺时针旋转,进入下一个方向。判断路径是否进入之前访问过,需要使用一个与输入矩阵大小相同的辅助矩阵 ,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将 中的对应位置的元素设为已访问。

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        visited = [[False] * columns for _ in range(rows)]
        total = rows * columns
        order = [0] * total

        directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
        row, column = 0, 0
        directionIndex = 0
        for i in range(total):
            order[i] = matrix[row][column]
            visited[row][column] = True
            nextRow, nextColumn = row + directions[directionIndex][0], column + directions[directionIndex][1]
            if not (0 <= nextRow < rows and 0 <= nextColumn < columns and not visited[nextRow][nextColumn]):
                directionIndex = (directionIndex + 1) % 4
            row += directions[directionIndex][0]
            column += directions[directionIndex][1]
        return order

普通写法2 (17行)

可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第1层,次外层元素都是第2层,剩下的元素都是第3层。

[[1, 1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1, 1]]

对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于,右下角位于 ,按照如下顺序遍历当前层的元素。

  • 从左到右遍历上侧元素,依次为到。
  • 从上到下遍历右侧元素,依次为到。
  • 如果且,则从右到左遍历下侧元素,依次为到
  • 以及从下到上遍历左侧元素,依次为到。
    遍历完当前层的元素之后,将和分别增加1,将和分别减少1,进入下一层继续遍历,直到遍历完所有元素为止。
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        order = list()
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
        while left <= right and top <= bottom:
            for column in range(left, right + 1):
                order.append(matrix[top][column])
            for row in range(top + 1, bottom + 1):
                order.append(matrix[row][right])
            if left < right and top < bottom:
                for column in range(right - 1, left, -1):
                    order.append(matrix[bottom][column])
                for row in range(bottom, top, -1):
                    order.append(matrix[row][left])
            left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
        return order

普通写法3(19行)

链接:https://www.nowcoder.com/questionTerminal/9b4c81a02cd34f76be2659fa0d54342a?toCommentId=1128425
来源:牛客网
模拟魔方逆时针旋转的方法,一直做取出第一行的操作。例如 :

1 2 3
4 5 6
7 8 9

输出并删除第一行后,再进行一次逆时针旋转,就变成:

6 9
5 8
4 7

继续重复上述操作即可。

class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        result = []
        while(matrix):
            result+=matrix.pop(0)
            if not matrix or not matrix[0]:
                break
            matrix = self.turn(matrix)
        return result
    def turn(self,matrix):
        num_r = len(matrix)
        num_c = len(matrix[0])
        newmat = []
        for i in range(num_c):
            newmat2 = []
            for j in range(num_r):
                newmat2.append(matrix[j][i])
            newmat.append(newmat2)
        newmat.reverse()
        return newmat

上帝之手(1行)

思路与解法3一样,每次取第一行并逆时针旋转,直到矩阵为空。

def spiralOrder(self, matrix):
        return matrix and list(matrix.pop(0)) + self.spiralOrder(zip(*matrix)[::-1])

技巧1:zip语句将矩阵按列重组,*matrix表示元组。zip(*matrix)将从第一列开始排到最后一列,[::-1]表示倒序,zip(*matrix)[::-1]表示matrix逆时针旋转一次。例子:

matrix = [[1, 2, 3],
          [4, 5, 6]]

zip(*matrix)

[(1, 4), 
 (2, 5),
 (3, 6)]

zip(*matrix)[::-1]

[(3, 6), 
 (2, 5), 
 (1, 4)]

技巧2:递归调用函数自身。这一步减少了代码量,代价是使用堆栈,运行会变慢。

你可能感兴趣的:(Stefan Pochmann 的上帝之手(2)旋转打印矩阵)