题目链接
https://leetcode-cn.com/problems/SNJvJP/
题目描述
某乐团的演出场地可视作 num * num 的二维矩阵 grid(左上角坐标为 [0,0]),每个位置站有一位成员。乐团共有 9 种乐器,乐器编号为 1~9,每位成员持有 1 个乐器。
为保证声乐混合效果,成员站位规则为:自 grid 左上角开始顺时针螺旋形向内循环以 1,2,...,9 循环重复排列。例如当 num = 5 时,站位如图所示:
请返回位于场地坐标 [Xpos
,Ypos
] 的成员所持乐器编号。1<=num<=10^9,0<=xPos,yPos < num。
示例
输入:num = 4,xPos = 1,yPos = 2
输出:5
解题思路
对于这类找数学规律的问题,我们要在充分理解题意的基础上通过举来挖掘规律。如果我们知道某位置是生成螺旋矩阵时的第res个数(从1开始计),我们可以很容易得到某个位置的乐器编号:如果res%9==0,那么乐器编号为9;如果res%9!=0,那么乐器编号就是res%9。(需要做判断,不能直接返回res%9)
。比如num=4的螺旋矩阵为:
比如对于x=2,y=1的位置,计数为16,那么乐器编号为16%9 = 7。如果直接遍历螺旋矩阵来得到计数的话,对于10^9的数据规模,O(N)的时间复杂度会导致TLE。因此我们要找规律来得到当前位置的计数。我们能够很容易观察到,螺旋矩阵是一圈一圈绕进去的,我们可以直接根据给定的矩阵边长,和当前位置(xPos,yPos)得到计数结果:
1、首先要确定当前位置所在的层数(从0开始计)。容易发现,层数是当前位置距离上、下、左、右四个边界的最小值min(xPos,num-1-xPos,yPos,num-1-yPos)。当前位置和上边界的距离为xPos,和下边界的距离为num-1-xPos,和左边界的距离为yPos,和右边界的距离为num-1-yPos。比如对于num=4的螺旋矩阵中的(1,3)位置,该位置距离上边界的距离为1,距离下边界的距离为2,距离左边界的距离为3,距离右边界的距离为0。因此(1,3)位置在螺旋矩阵的第0层。记当前位置在螺旋矩阵的第k层。
2、确定当前位置所在层数后,我们要知道层数小于当前层(环绕当前层)的层中有多少个元素,因为这些元素一定都在当前位置的前面。在计数走到当前层的当前位置之前,环绕当前层的层一定已经被填满了。
得到环绕当前层的层中元素个数有两种方法:
(1)我们根据num=5的螺旋矩阵找规律:
第k层的边长为n-2k,由此也很容易能得出第k层的元素个数4*(n-2k-1)),第0层的元素个数为4*(n-1),第1层的元素个数4*(n-2-1),每层的元素个数构成公差为8的等差序列。因此如果当前位置在第k层,那么从第0层到第k-1层(共有k层)的元素总和为((4*(n-1) + 4*(n-2(k-1)-1))*(k))/2 = 4k(n-k)。
(2)让大正方形中元素个数减去当前层所在的小正方形中元素个数。大正方形中元素个数为n*n,小正方形的边长为(n-2k),因此结果为n*n-(n-2k)*(n-2k) = 4k(n-k)。
3、最后计算当前位置是生成当前层时的第几个值(从1开始计数),这要看当前位置在这一层上、下、左、右中的哪个位置,当前层所在小正方形的边长为size = n-2k,当前层(第k层)所构成的正方形的左上角坐标为(k,k),(k,k)是当前层中的第一个元素。我们令x = xPos-k,y = yPos-k,那么x,y分别是当前位置以(k,k)为坐标原点时的相对坐标。
(我们得到下面公式时要举个例子看是否正确,也可以通过例子倒推公式)
如果x==0,那么当前位置在第k层的上边界,当前位置是当前层的第y+1个值。
如果y==size-1,那么当前位置在第k层的右边界,当前位置是当前层的第size+x个值。
如果x==size-1,那么当前位置在第k层的下边界,当前位置是当前层的第2*(size-1)+size-y个值。
如果y==0,那么当前位置在第k层的左边界,当前位置是当前层的第3*(size-1)+size-x个值。
Python实现
class Solution:
def orchestraLayout(self, num: int, xPos: int, yPos: int) -> int:
res = 0
k = min(xPos,yPos,num-1-xPos,num-1-yPos) #当前所在层数
res += 4*k*(num-k) #环绕当前层的层中元素个数
size = num-2*k #size为当前层边长
x = xPos-k#相对坐标
y = yPos-k #相对坐标
if(x == 0): #在上边界
res += (y+1)
elif(y == size-1):#在右边界
res += (size+x)
elif(x == size -1): #在下边界
res += 2*(size-1) +size-y
else:#在左边界
res += 3*(size-1) + size-x
return 9 if res%9==0 else res%9