题目:
Given an n x n array, return the array elements arranged from outermost elements to the middle element, traveling clockwise.
array = [[1,2,3],
[4,5,6],
[7,8,9]]
snail(array) #=> [1,2,3,6,9,8,7,4,5]
For better understanding, please follow the numbers of the next array consecutively:
array = [[1,2,3],
[8,9,4],
[7,6,5]]
snail(array) #=> [1,2,3,4,5,6,7,8,9]
This image will illustrate things more clearly:
NOTE: The idea is not sort the elements from the lowest value to the highest; the idea is to traverse the 2-d array in a clockwise snailshell pattern.
NOTE 2: The 0x0 (empty matrix) is represented as en empty array inside an array [[]].
我的思路:
题目就是让我们按顺时针方向,由外向里获取二维数组中的数字。
数组是正方形的,获取一圈数字后剩下的还是正方形。我构造了两个function,一个是 get_outer() ,用来获取最外圈数字;一个是 cut_outer() ,用来把最外圈削掉,变成一个新的小一圈的正方形。当正方形边长大于等于3时,循环获取和削除的过程,最后边长为1或2时再获取一次。
我的解答:
def snail(snail_map):
result = []
while len(snail_map) >= 3:
result = result + get_outer(snail_map)
snail_map = cut_outer(snail_map)
result = result + get_outer(snail_map)
return result
def get_outer(map):
n = len(map)
if n == 1:
return map[0]
first = map[0]
second = []
if n >= 3:
for i in range(1,n-1):
second.append(map[i][n-1])
third = map[n-1]
third.reverse()
fourth = []
if n >= 3:
for j in range(1,n-1):
fourth.append(map[j][0])
fourth.reverse()
return first + second + third + fourth
def cut_outer(map):
n = len(map)
new = []
for i in range(1,n-1):
new.append(map[i][1:n-1])
return new
Most Clever:
做完题目看一下题后投票clever最多的答案:
def snail(array):
return list(array[0]) + snail(zip(*array[1:])[::-1]) if array else []
大佬一句话就解决了。
其中 zip() 我没有见过,查了一下:
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
自己试一下:
由于是规整的二维数组,zip() 相当于把数组沿“左上-右下“”对角线翻转,然后 [::-1] 相当于沿垂直中线翻转,两个操作合起来相当于顺时针旋转90度。
用递归不断调用自己,每一次调用都先将第一行加入list,然后把矩阵顺时针旋转90度。非常巧妙。
总结:
学会了 zip() 的用法,Most Clever的答案很巧妙地控制矩阵变形,过程简单而且形象。