54螺旋矩阵
1. 题目描述
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例:
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
输入: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
2. 题目解答
2.1 按层模拟
思路:可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PROoGdvS-1631255569369)(F:\0. Note\Typora-image\latex\54_fig1.png)]
- 从左到右遍历上侧元素,依次为$ (\textit{top}, \textit{left}) 到 到 到 (\textit{top}, \textit{right})$
- 从上到下遍历右侧元素,依次为 ( top + 1 , right ) (\textit{top} + 1, \textit{right}) (top+1,right)到 ( bottom , right ) (\textit{bottom}, \textit{right}) (bottom,right)
- 如果
left
<
right
\textit{left} < \textit{right}
left<right且$ \textit{top} < \textit{bottom}$:
- 则从右到左遍历下侧元素,依次为$ (\textit{bottom}, \textit{right} - 1) $到 ( bottom , left + 1 ) (\textit{bottom}, \textit{left} + 1) (bottom,left+1)
- 从下到上遍历左侧元素,依次为$ (\textit{bottom}, \textit{left}) 到 到 到 (\textit{top} + 1, \textit{left})$
- 遍历完当前层的元素之后,将$ \textit{left} 和 和 和 \textit{top} 分 别 增 加 1 , 将 分别增加 1,将 分别增加1,将 \textit{right} $和 bottom \textit{bottom} bottom分别减少 1,进入下一层继续遍历,直到遍历完所有元素为止。
时间复杂度: O ( m n ) O(mn) O(mn), 其中 m m m 和 $n $分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。
空间复杂度: O ( 1 ) O(1) O(1),除了输出数组以外,空间复杂度是常数
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix or not matrix[0]:
return list()
row, col = len(matrix), len(matrix[0])
left, right, top, bottom = 0, col - 1, 0, row - 1
res = []
while left <= right and top <= bottom: # =成立时是最里面的一层
for c in range(left, right + 1):
res.append(matrix[top][c])
for r in range(top + 1, bottom + 1):
res.append(matrix[r][right])
if left < right and top < bottom: # 避免只有一行t=b或一列的情况l=r,其余情况两者不相等
for c in range(right - 1, left, -1):
res.append(matrix[bottom][c])
for r in range(bottom, top, -1):
res.append(matrix[r][left])
left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
return res
2.2 模拟
遍历题目思考清楚以下问题:
- 起始位置
- 移动方向
- 边界
- 结束条件
算法思路:
- top, bottom, left, right 分别表示四个方向的边界。
- x, y 表示当前位置。
- direction 分别表示移动方向是 右、下、左、上 。
- index表示当前的移动方向的下标,direction[index] 就是下一个方向需要怎么修改 x, y。
- index == 0 and y == right 表示当前的移动方向是向右,并且到达了右边界,此时将移动方向更改为向下,并且上边界 top 向下移动一格。
- 结束条件是结果数组 res 的元素个数能与 matrix 中的元素个数。
时间复杂度:
O
(
m
n
)
O(mn)
O(mn)
空间复杂度:
O
(
1
)
O(1)
O(1),除了输出数组以外,空间复杂度是常数
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix or not matrix[0]:
return []
row, col = len(matrix), len(matrix[0])
left, right, top, bottom = 0, col - 1, 0, row - 1 # 边界
x, y = 0, 0 # 起始位置
directions = [[0, 1], [1, 0], [0, -1], [-1, 0]] # 移动方向[(0, 1), (1, 0), (0, -1), (-1, 0)]
index = 0 # directions下标
res = []
while len(res) != row * col: # 结束条件
res.append(matrix[x][y])
if index == 0 and y == right:
index += 1
top += 1
elif index == 1 and x == bottom:
index += 1
right -= 1
elif index == 2 and y == left: # bug y写成了x
index += 1
bottom -= 1
elif index == 3 and x == top: # 已经被赋值了新top值
index += 1
left += 1
index %= 4
x += directions[index][0]
y += directions[index][1]
return res
3. 错解
59螺旋矩阵Ⅱ
1. 题目描述
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例:
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
[[1]]
输入:n = 1
输出:[[1]]
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
2. 题目解答
2.1 尝试-按层模拟
思路:
- 生成所有的元素一维数组res,将每个值依次放入matrix的对应位置
- matrix的位置一层一层指定索引
时间复杂度: O ( n 2 ) O(n^2) O(n2) 其中 n 是给定的正整数。矩阵的大小是 n × n n \times n n×n,需要填入矩阵中的每个元素。
空间复杂度: O ( 1 ) O(1) O(1),除了返回的矩阵以外,空间复杂度是常数
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
res = [i for i in range(1, n*n + 1)]
matrix = [[0]*n for i in range(n)] # 生成一个空矩阵,将res里的元素逐个放入
left, right, top, bottom = 0, n - 1, 0, n - 1 # 边界
i = 0
while left <= right and top <= bottom:
for c in range(left, right + 1):
matrix[top][c] = res[i]
i += 1
for r in range(top + 1, bottom + 1):
matrix[r][right] = res[i]
i += 1
for c in range(right - 1, left, -1):
matrix[bottom][c] = res[i]
i += 1
for r in range(bottom, top, -1):
matrix[r][left] = res[i]
i += 1
left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
return matrix
改进:去除res数组
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
matrix = [[0]*n for i in range(n)] # 生成一个空矩阵,将res里的元素逐个放入
left, right, top, bottom = 0, n - 1, 0, n - 1 # 边界
i = 0
res = 1
while left <= right and top <= bottom:
for c in range(left, right + 1): # 统一左闭右开要除了第一行,考虑最里面取一个值情况
matrix[top][c] = res
res += 1
for r in range(top + 1, bottom):
matrix[r][right] = res
res += 1
for c in range(right, left, -1):
matrix[bottom][c] = res
res += 1
for r in range(bottom, top, -1):
matrix[r][left] = res
res += 1
left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
return matrix
改进:去除res数组/统一左闭右开,n为奇数要额外填充一次中心
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
matrix = [[0]*n for i in range(n)] # 生成一个空矩阵,将res里的元素逐个放入
left, right, top, bottom = 0, n - 1, 0, n - 1 # 边界
i = 0
res = 1
while left <= right and top <= bottom:
for c in range(left, right): # 统一左闭右开
matrix[top][c] = res
res += 1
for r in range(top, bottom):
matrix[r][right] = res
res += 1
for c in range(right, left, -1):
matrix[bottom][c] = res
res += 1
for r in range(bottom, top, -1):
matrix[r][left] = res
res += 1
left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
# 如果阶数为奇数,额外填充一次中心
if n % 2:
matrix[n // 2][n // 2] = res
return matrix
2.2 模拟
遍历题目思考清楚以下问题:
- 起始位置
- 移动方向
- 边界
- 结束条件
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1),除了输出数组以外,空间复杂度是常数
class Solution: def generateMatrix(self, n: int) -> List[List[int]]: left, right, top, bottom = 0, n - 1, 0, n - 1 # 边界 x, y = 0, 0 # 起始位置 directions = [[0, 1], [1, 0], [0, -1], [-1, 0]] # 移动方向[(0, 1), (1, 0), (0, -1), (-1, 0)] index = 0 # directions下标 res = 1 matrix = [[0]*n for i in range(n)] while res <= n*n: # 结束条件 matrix[x][y] = res res += 1 if index == 0 and y == right: index += 1 top += 1 elif index == 1 and x == bottom: index += 1 right -= 1 elif index == 2 and y == left: # bug y写成了x index += 1 bottom -= 1 elif index == 3 and x == top: # 已经被赋值了新top值 index += 1 left += 1 index %= 4 x += directions[index][0] y += directions[index][1] return matrix
3. 错解
885螺旋矩阵Ⅲ
1. 题目描述
在
R
R
R 行
C
C
C 列的矩阵上,我们从
(
r
0
,
c
0
)
(r_0, c_0)
(r0,c0) 面朝东面开始。这里,网格的西北角位于第一行第一列,网格的东南角位于最后一行最后一列。
现在,我们以顺时针按螺旋状行走,访问此网格中的每个位置。每当我们移动到网格的边界之外时,我们会继续在网格之外行走(但稍后可能会返回到网格边界)。
最终,我们到过网格的所有 R * C 个空间。
按照访问顺序返回表示网格位置的坐标列表。
示例1:
输入:R = 1, C = 4, r0 = 0, c0 = 0输出:[[0,0],[0,1],[0,2],[0,3]]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9y8QrNp-1631255569370)(F:\0. Note\Typora-image\latex\example_1.png)]
示例2:
输入:R = 5, C = 6, r0 = 1, c0 = 4输出:[[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ifpXQxp3-1631255569371)(F:\0. Note\Typora-image\latex\example_2.png)]
提示:
1 <= R <= 100
1 <= C <= 100
0 <= r_0 < R
0 <= c_0 < C
2. 题目解答
2.1 模拟
思路:
1.确立四个边界Left, Right, Upper, Bottom;
2.当一个方向达到边界时,调整方向;
3.根据方向更新下一个节点
4.当节点在矩阵范围内,则加入到res中
时间复杂度: O ( m a x ( R , C ) 2 ) O(max(R,C)^2) O(max(R,C)2)
空间复杂度: O ( 1 ) O(1) O(1),结果需要 R ∗ C R*C R∗C
class Solution: def spiralMatrixIII(self, rows: int, cols: int, rStart: int, cStart: int) -> List[List[int]]: res = [] around = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 顺时针方向,每次绕一个正方形 Left, Right, Upper, Bottom = cStart - 1, cStart + 1, rStart - 1, rStart + 1 ##四个方向的边界 x, y, num, Dir = rStart, cStart, 1, 0 ##(x, y)为当前节点,num为当前查找的数字,Dir为当前的方向 while num <= rows * cols: if x >= 0 and x < rows and y >= 0 and y < cols: ##(x, y)在矩阵中 res.append([x, y]) num += 1 if Dir == 0 and y == Right: ##向右到右边界 Dir += 1 ##调转方向向下 Right += 1 ##右边界右移 elif Dir == 1 and x == Bottom: ##向下到底边界 Dir += 1 Bottom += 1 ##底边界下移 elif Dir == 2 and y == Left: ##向左到左边界 Dir += 1 Left -= 1 ##左边界左移 elif Dir == 3 and x == Upper: ##向上到上边界 Dir = 0 Upper -= 1 ##上边界上移 x += around[Dir][0] y += around[Dir][1] return res
3. 错解
- 剑指Offer 29.顺时针打印矩阵