剑指 Offer 29. 顺时针打印矩阵
Posted 炫云云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 29. 顺时针打印矩阵相关的知识,希望对你有一定的参考价值。
剑指 Offer 29. 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 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]
限制:
0 < = m a t r i x . l e n g t h < = 100 0 <= matrix.length <= 100 0<=matrix.length<=100
模拟
根据题目示例 matrix = [[1,2,3],[4,5,6],[7,8,9]]
的对应输出 [1,2,3,6,9,8,7,4,5]
可以发现,顺时针打印矩阵的顺序是 “从左向右、从上向下、从右向左、从下向上” 循环。
因此,考虑设定矩阵的“左、上、右、下”四个边界,模拟以上矩阵遍历顺序。
可以模拟打印矩阵的路径。初始位置是矩阵的左上角,初始方向是向右,当路径超出界限或者进入之前访问过的位置时,顺时针旋转,进入下一个方向。
判断路径是否进入之前访问过的位置需要使用一个与输入矩阵大小相同的辅助矩阵 visited \\textit{visited} visited ,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将 visited \\textit{visited} visited 中的对应位置的元素设为已访问。
如何判断路径是否结束?由于矩阵中的每个元素都被访问一次,因此路径的长度即为矩阵中的元素数量,当路径的长度达到矩阵中的元素数量时即为完整路径,将该路径返回。
class Solution(object):
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: 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 # 当nextColumn和nextRow>3时,加1
row += directions[directionIndex][0]
column += directions[directionIndex][1] # 右: 0 1 ,0 2 ,0 3 ;下:1 3,2 3;左:2 2,2 1,2 0;上:1 0,右:1 1,1 2
return order
a = Solution()
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
a.spiralOrder(matrix)
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
算法流程:
- 空值处理: 当
matrix
为空时,直接返回空列表[]
即可。 - 初始化: 矩阵 左、右、上、下 四个边界
l , r , t , b
,用于打印的结果列表res
。 - 循环打印 : “从左向右、从上向下、从右向左、从下向上” 四个方向循环,每个方向打印中做以下三件事 (各方向的具体信息见下表) ;
-
- 根据边界打印,即将元素按顺序添加至列表 res 尾部;
-
- 边界向内收缩 1 (代表已被打印);
-
- 判断是否打印完毕(边界是否相遇),若打印完毕则跳出。
- 返回值: 返回 res 即可。
打印方向 | 1. 根据边界打印 | 2. 边界向内收缩 | 3. 是否打印完毕 |
---|---|---|---|
从左向右 | 左边界l ,右边界 r | 上边界 t 加 1 | 是否 t > b |
从上向下 | 上边界 t ,下边界b | 右边界 r 减 1 | 是否 l > r |
从右向左 | 右边界 r ,左边界l | 下边界 b 减 1 | 是否 t > b |
从下向上 | 下边界 b ,上边界t | 左边界 l 加 1 | 是否 l > r |
class Solution(object):
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
if not matrix:
return []
l, r, t, b, res = 0, len(matrix[0]) - 1, 0, len(matrix) - 1, []
while True:
for i in range(l,r+1):
res.append(matrix[t][i]) # left to right
t += 1 #上边界下降
if t > b:
break
for i in range(t, b+1):
res.append(matrix[i][r]) # top to bottom
r-=1 #右边界左移
if l > r:
break
for i in range(r, l-1,-1):
res.append(matrix[b][i])# right to left
b -= 1 #下边界上移
if t > b:
break
for i in range(b,t-1,-1):
res.append(matrix[i][l]) # bottom to top
l += 1 #左边界右移
if l > r: break
return res
将矩阵第一行的元素添加到 res
列表里,删除第一行(也就是 matrix
中的第一个列表),然后逆时针旋转(这里通过转置+倒序实现),新的 matrix
的第一行即为接下来要打印的元素。
class Solution(object):
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
res = []
while matrix:
res += matrix.pop(0)
matrix = list(zip(*matrix))[::-1]
return res
参考
以上是关于剑指 Offer 29. 顺时针打印矩阵的主要内容,如果未能解决你的问题,请参考以下文章