感想
最近刷了几天 CodeWars, 感想颇多。CodeWars 更多的关注的是编程基础和语言特性,算法的比重小一点,测试用例也不怎么有边界情况,所以刷起来比较轻松有意思。刷了几天,感觉自己的编程水平又下降了。
感想如下:
一是见识到了很多从来都没用过而且大概率从来不会去用的库函数,比如
str.center()
二是见识到了那些疯狂写
one-liner
的 python 程序员。一个函数一定能用一行实现,如果不能,就两行。执行效率?不存在的。三是我 haskell 白学了,看到题还是不知道咋写。练习不够,没熟悉函数式编程的套路,罢了罢了。
一道题目
写这篇博客的主要原因是被一道题目的 one-liner 深深折服。
题目很简单,就是顺时针遍历二维数组,大部分人在初学 C++ 的时候肯定都写过吧。但是如果结合语言特性,就会衍生出神奇的解法。
我的低幼解法
我的解法很弱智,就是四个方向分别遍历,判断下边界。
def snail(array):
x, y = 0, 0
row, col = len(array), len(array[0])
l = row * col if row == col else 0
vis = array.copy()
res = []
drct = ((0,1),(1,0),(0,-1),(-1,0))
d = 0
for i in range(l):
res.append(array[x][y])
vis[x][y] = 'X'
if ( x + drct[d][0] < 0 or x + drct[d][0] >= row or
y + y + drct[d][1] < 0 or y + drct[d][1] >= col or
vis[x + drct[d][0]][y + drct[d][1]] == 'X'):
d = (d + 1) % 4
x += drct[d][0]
y += drct[d][1]
return res
比较正常的解法
这个思路很清晰,就是预先算好每次遍历某行/列时走过的数字个数,然后也是四个方向轮转,比我写的好看很多。(主要是我懒得计算了)
def _snail(array):
n = len(array)
for a in range(0, (n + 1) // 2):
b = n - 1 - a
for j in range(a, b + 1):
yield array[a][j]
for i in range(a + 1, b + 1):
yield array[i][b]
for j in range(b - 1, a - 1, -1):
yield array[b][j]
for i in range(b - 1, a, -1):
yield array[i][a]
def snail(array):
return list(_snail(array)) if array and array[0] else []
摘抄自 用户 biskinis
one-liner 递归解法
这个是 CodeWars 里面投出的最聪明的做法
这种方法我是真的想不到…评论下面也是一片叫好声
def snail(array):
return list(array[0]) + snail(zip(*array[1:])[::-1]) if array else []
解释: 就是每次取出一行,将剩下的数组巧妙地用 zip 函数逆时针翻转,然后继续递归求解,直到数组为空。
顺便一说,如果不强求 one-liner, 递归改成循环会更容易看懂。
最后
哇,我这篇博客写的真是太水了……