鱼C论坛

 找回密码
 立即注册
查看: 3435|回复: 23

[已解决]Python:每日一题 291

[复制链接]
发表于 2019-12-18 20:37:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 zltzlt 于 2019-12-18 22:09 编辑

今天的题目:


给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵

示例 1:

输入:2
输出:
[
[1, 2],
[4, 3],
]
示例 2:

输入:3
输出:
[
[1, 2, 3],
[8, 9, 4],
[7, 6, 5]
]


欢迎大家一起答题!
最佳答案
2019-12-19 01:45:26
  1. def func(self, n):
  2.     ret = [[0] * n for _ in range(n)]
  3.     i, j, di, dj = 0, 0, 0, 1
  4.     for k in xrange(n*n):
  5.         ret[i][j] = k + 1
  6.         if ret[(i+di)%n][(j+dj)%n]:
  7.             di, dj = dj, -di
  8.         i += di
  9.         j += dj
  10.     return ret
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-12-18 20:42:20 | 显示全部楼层
本帖最后由 小小小菜菜菜 于 2019-12-18 20:47 编辑

改成这样
  1. def get_matrix(n=4):

  2.     abc = [[0 for i in range(n)] for j in range(n)]
  3.     i = 1
  4.     k = 0

  5.     while i < n**2:
  6.         for u in range(0+k, n-1-k):
  7.             abc[0+k][u] = i
  8.             i += 1

  9.         for r in range(0+k, n-1-k):
  10.             abc[r][n-1-k] = i
  11.             i += 1

  12.         for d in range(n-1-k, 0+k, -1):
  13.             abc[n-1-k][d] = i
  14.             i += 1

  15.         for l in range(n-1-k, 0+k, -1):
  16.             abc[l][0+k] = i
  17.             i += 1

  18.         k += 1

  19.     if n%2 != 0:
  20.         abc[k][k] = n**2

  21.     return abc
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +3 收起 理由
zltzlt + 3 + 3 + 3 28 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-12-18 20:43:08 | 显示全部楼层

不能使用第三方库哦。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 21:18:59 | 显示全部楼层
n最大多大
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 21:29:23 | 显示全部楼层

上不设限

                               
登录/注册后可看大图
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 21:33:16 | 显示全部楼层
楼主,示例1的输出把逗号漏掉了真的好吗?
  1. def solve(n:int)->list:
  2.     def get_pos():
  3.         side = [0,n,0,n]#[上,下,左,右]
  4.         y = x = 0
  5.         while side[1]-side[0] or side[3]-side[2]:#未完
  6.             for y in range(side[2],side[3]):#向右
  7.                 yield (x,y)
  8.             else:
  9.                 side[0] += (1 if side[0]<side[1] else 0)
  10.             for x in range(side[0],side[1]):#向下
  11.                 yield (x,y)
  12.             else:
  13.                 side[3] -= (1 if side[3]>side[2] else 0)
  14.             for y in range(side[3]-1,side[2]-1,-1):#向左
  15.                 yield (x,y)
  16.             else:
  17.                 side[1] -= (1 if side[1]>side[0] else 0)
  18.             for x in range(side[1]-1,side[0]-1,-1):#向上
  19.                 yield (x,y)
  20.             else:
  21.                 side[2] += (1 if side[2]<side[3] else 0)
  22.     res = [[0]*n for i in range(n)]
  23.     num = 1
  24.     for pos in get_pos():
  25.         x,y = pos
  26.         res[x][y] = num
  27.         num += 1
  28.     return res

  29. if __name__ == '__main__':
  30.     print('示例1 输出:',solve(2))
  31.     print('示例2 输出:',solve(3))
  32.     print('自测 输出:',solve(1),solve(0))
复制代码

我来康康差不多的逻辑,楼主能变出什么花儿来

                               
登录/注册后可看大图

                               
登录/注册后可看大图

                               
登录/注册后可看大图

时间复杂度应当为 O(n^2)

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +3 收起 理由
zltzlt + 3 + 3 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-12-18 22:16:02 | 显示全部楼层
阴阳神万物主 发表于 2019-12-18 21:33
楼主,示例1的输出把逗号漏掉了真的好吗?

我来康康差不多的逻辑,楼主能变出什么花儿来


当然是通过啦

执行用时:24 ms
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 22:24:25 | 显示全部楼层
zltzlt 发表于 2019-12-18 22:16
当然是通过啦

执行用时:24 ms

要不是定义一个类可能算开挂,我就定义类了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 22:56:23 | 显示全部楼层
本帖最后由 Croper 于 2019-12-18 22:59 编辑

拙劣模仿冬雪雪冬大佬的zip法:
  1. def func291_1(n):
  2.     if (n==0):
  3.         return []
  4.     ret=[[n**2]]
  5.     i=n**2;
  6.     while (i>1):
  7.         ret=[list(c) for c in zip(*reversed(ret))]
  8.         ret.insert(0,list(range(i-len(ret[0]),i)))
  9.         i-=len(ret[0])
  10.     return ret;
复制代码


数学法:
  1. def func291_2(n):
  2.     ret=[];
  3.     for y in range(n):
  4.         ret.append([])
  5.         for x in range(n):
  6.             layer=min(x,y,n-1-x,n-1-y);
  7.             i=(x+y-2*layer+1) if (x==n-1-layer or y==layer) else (4*n-6*layer-3-x-y)
  8.             ret[y].append(4*(n-layer)*layer+i);
  9.     return ret;
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
zltzlt + 3 + 3 + 2 36 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 23:20:15 | 显示全部楼层
速度有点慢 实测 1000时 我的代码耗时 大约 3.5秒左右 不甚理想
  1. def fun291(n):
  2.     def getNum(x,y,num):
  3.         #判断圈数
  4.         loop = min([x,y,num-1-x,num-1-y])
  5.         firstNum = 0
  6.         if loop > 0:
  7.             firstNum = 1 + 4 * num * loop - 4 * loop *loop
  8.         else:
  9.             firstNum = 1
  10.         #四个标记位
  11.         if x == loop:
  12.             return firstNum + (pointy - loop)
  13.         elif y == num - 1 - loop:
  14.             return firstNum + (num - 1 - 2*loop) + (pointx - loop)
  15.         elif x == num - loop - 1:
  16.             return firstNum + (num - 1 - 2*loop) + (num - 1 - 2*loop) + (num - 1 - loop- pointy)
  17.         else:
  18.             return firstNum + (num - 1 - 2*loop) + (num - 1 - 2*loop) + (num - 1 - 2*loop) + (num - 1 - loop - pointx)

  19.         
  20.     result = []
  21.     for pointx in range(0,n):
  22.         line = []
  23.         for pointy in range(0,n):
  24.             element = getNum(pointx,pointy,n)
  25.             line.append(element)
  26.         result.append(line)
  27.     return result
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
zltzlt + 3 + 3 + 2 36 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-18 23:22:36 | 显示全部楼层
阴阳神万物主 发表于 2019-12-18 21:33
楼主,示例1的输出把逗号漏掉了真的好吗?

我来康康差不多的逻辑,楼主能变出什么花儿来

你这个方法不错,我觉得应该是好东西
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 01:45:26 | 显示全部楼层    本楼为最佳答案   
  1. def func(self, n):
  2.     ret = [[0] * n for _ in range(n)]
  3.     i, j, di, dj = 0, 0, 0, 1
  4.     for k in xrange(n*n):
  5.         ret[i][j] = k + 1
  6.         if ret[(i+di)%n][(j+dj)%n]:
  7.             di, dj = dj, -di
  8.         i += di
  9.         j += dj
  10.     return ret
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +3 收起 理由
zltzlt + 3 + 3 + 3 20 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 01:59:43 | 显示全部楼层
阴阳神万物主 发表于 2019-12-18 21:33
楼主,示例1的输出把逗号漏掉了真的好吗?

我来康康差不多的逻辑,楼主能变出什么花儿来

大佬你的数学逻辑是怎么练出来的,我看这些想到一半就开始头晕
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 09:32:56 | 显示全部楼层

这个思路妙,不过func不用self,而且也没有xrange
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 10:02:17 | 显示全部楼层

  1. def func(n):
  2.     list1 = [[] for i in range(n)]
  3.     number = 0
  4.     count = 0
  5.    
  6.     while count < ((n//2) + (n%2)):
  7.         temp = (n-2*count-1)*4
  8.         if temp == 0:
  9.             list1[n//2].insert(n//2,number+1)
  10.             break
  11.         
  12.         for i in range(number + temp//4 + 1,number,-1):
  13.             list1[count].insert(count,i)
  14.         
  15.         for i in range(number + temp//4 + 2,number + (temp//4)*2 + 1):
  16.             list1[count+i-number-temp//4-1].insert(count,i)
  17.         
  18.         for i in range(number + (temp//4)*2 + 1,number + (temp//4)*3 + 2):
  19.             list1[-count-1].insert(count,i)
  20.         
  21.         for i in range(number + (temp//4)*3 + 2,number + (temp//4)*4 + 1):
  22.             list1[-count-i+number+(temp//4)*3].insert(count,i)
  23.         
  24.         number += temp
  25.         count += 1
  26.    
  27.     return list1
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
zltzlt + 3 + 3 + 2 36 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 12:10:20 | 显示全部楼层
hrp 发表于 2019-12-19 01:59
大佬你的数学逻辑是怎么练出来的,我看这些想到一半就开始头晕

这不是数学逻辑,仅仅是逻辑,涉及数学的不过只有建立了一个 平面直角坐标系 而已。
然后将 (0,0) 到 (n-1,n-1) 的连线作为正方形的对角线,再把正方形画出来,顺时针沿着正方形的边走,越走越往内而已呀,走一格报一个坐标,按照题意绕圈圈啊。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 14:22:14 | 显示全部楼层
阴阳神万物主 发表于 2019-12-19 12:10
这不是数学逻辑,仅仅是逻辑,涉及数学的不过只有建立了一个 平面直角坐标系 而已。
然后将 (0,0) 到 (n ...

主要是这个生成器用的好,要是我可能就用序列或者其他结构记录了,你这样速度和空间都节省了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 16:57:04 | 显示全部楼层
本帖最后由 Stubborn 于 2019-12-19 16:58 编辑
  1. def fun291(n: int):
  2.     r, n = [[n ** 2]], n ** 2
  3.     while n > 1: n, r = n - len(r), [[*range(n - len(r), n)]] + [*zip(*r[::-1])]
  4.     return r
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
zltzlt + 3 + 3 + 2 36 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-19 18:31:49 | 显示全部楼层
  1. def fun291(n):
  2.     temp_list = [[0]*n for i in range(n)]
  3.     i,j = 0,0
  4.     i_b,j_b = 0,1
  5.     boo_pool= [(0,1),(1,0),(0,-1),(-1,0)]
  6.     m = 0
  7.     for _ in range(n*n):
  8.         temp_list[i][j] = _+1
  9.         i += i_b
  10.         j += j_b
  11.         try:
  12.             if temp_list[i+i_b][j+j_b] != 0:
  13.                 m += 1
  14.                 i_b,j_b = boo_pool[m%4]
  15.         except:
  16.             m += 1
  17.             i_b,j_b = boo_pool[m%4]
  18.     return temp_list
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
zltzlt + 3 + 3 + 2 52 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-12-20 00:57:01 | 显示全部楼层
命名不规范,写的有点乱所以加了注释,没有用递归
  1. def solve(n):
  2.     # 生成n * n的矩阵result,并且用0占位
  3.     result = []
  4.     for i in range(n):
  5.         result.append([])
  6.     for i in range(n):
  7.         for j in range(n):
  8.             result[i].append(0)
  9.     # 将填入的所有数字放入列表list1
  10.     list1 = list(range(1,n ** 2 + 1))
  11.     pile_num = 0 # 矩阵赋值的第pile_num层
  12.     while 1:
  13.         if len(list1) > 1:
  14.             # 对result的第pile_num层赋值,赋值方法:按行赋值,赋前n - 1个数,后旋转,循环四次即赋慢一层的值
  15.             rot_count = 4 # 旋转次数
  16.             while rot_count > 0:
  17.                 # 赋第pile_num层的第一行的前n - 1个数
  18.                 for i in range(pile_num,n - 1 - pile_num):
  19.                     result[pile_num][i] = list1[0]
  20.                     del list1[0]
  21.                 # 复制当前result给list2
  22.                 list2 = []
  23.                 for i in range(n):
  24.                     list2.append([])
  25.                 for i in range(n):
  26.                     for j in range(n):
  27.                         list2[i].append(result[i][j])
  28.                 # 利用list2使result逆时针旋转
  29.                 for i in range(n):
  30.                     for j in range(n):
  31.                         result[i][j] = list2[j][n - i - 1]
  32.                 rot_count -= 1
  33.             pile_num += 1
  34.         elif len(list1) == 1:
  35.             result[n // 2][n // 2] = list1[0]
  36.             del list1[0]
  37.         else:
  38.             break
  39.     return result

  40. if __name__ == '__main__':
  41.     print('自测1:')
  42.     result1 = solve(2)
  43.     for i in range(len(result1)):
  44.         print(result1[i])

  45.     print('自测2:')
  46.     result1 = solve(3)
  47.     for i in range(len(result1)):
  48.         print(result1[i])

  49.     print('自测1:')
  50.     result1 = solve(5)
  51.     for i in range(len(result1)):
  52.         print(result1[i])
复制代码

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
zltzlt + 3 + 3 + 2 56 ms

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-28 20:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表