我想旋转(逆时针)2D nxn整数数组,2D数组存储为列表列表。
例如:
a = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
旋转后,输出应如下所示:
b = [[3, 6, 9],
[2, 5, 8],
[1, 4, 7]]
我写了一个执行上述旋转的函数:
def rotate_clockwise(matrix):
transposed_matrix = zip(*matrix) # transpose the matrix
return list(map(list, reversed(transposed_matrix))) # reverse the transposed matrix
该功能运行良好,代码对我来说看起来很Pythonic。 但是,我无法理解我的解决方案的空间和时间复杂性。
有人可以解释我使用的构造的复杂性,即zip(*matrix)
,reversed(list)
,map(list, iterator)
和list(iterator)
吗?
如何使此代码更高效? 另外,旋转2D矩阵的最有效方法是什么?
注意:正如@Colonder在评论中所提到的,可能存在类似的问题。但是,这个问题更侧重于讨论问题的时空复杂性。
答案 0 :(得分:2)
效率最高的可能就是使用numpy
:
>>> import numpy as np
>>> na = np.array(a)
>>> np.rot90(na)
array([[3, 6, 9],
[2, 5, 8],
[1, 4, 7]])
关于您当前方法的效率。如果矩阵是 n×n - 矩阵,则zip
将在 O(n 2 )中工作,{{1这将在 O(n)中工作(因为它以浅层方式执行),reversed
函数将在 O(n)中工作,但我们这样做 n 次,因为它是在list
完成的,所以map(..)
将在 O(n 2 )< / em>的。最后,外部列表将再次在 O(n)中工作。但是,无法在少于 O(n 2 )中轮换显式,因为我们需要移动 O(n < sup> 2 )项目。
就空间复杂度而言map(list,..)
,zip
等以迭代方式工作。但map
会强制reversed
完全枚举的事实。来自zip
的每个元组都需要 O(n),因此分配的内存总量将为 O(n 2 )。接下来,zip
再次迭代工作,每个元组将转换为一个列表,再次需要 O(n)。我们这样做 n 次。因此它会产生 O(n 2 )内存复杂性。
在numpy中,如果你不在原地旋转,这将需要 O(n 2 ):这是一个下限,因为新矩阵将需要 O(n 2 )记忆。但是,如果你旋转 inplace ,内存的复杂性可以减少为 O(1)。