Lccup 力扣杯春季编程大赛 2. 乐团站位 给定坐标和阶数 求螺旋数组中对应下标的值

题目

        某乐团的演出场地可视作 num * num 的二维矩阵 grid(左上角坐标为 [0,0]),每个位置站有一位成员。乐团共有 9 种乐器,乐器编号为 1~9,每位成员持有 1 个乐器。

        为保证声乐混合效果,成员站位规则为:自 grid 左上角开始顺时针螺旋形向内循环以 1,2,...,9 循环重复排列。例如当 num = 5 时,站位如图所示

在这里插入图片描述

        请返回位于场地坐标 [Xpos,Ypos] 的成员所持乐器编号。

示例 1:

输入:num = 3, Xpos = 0, Ypos = 2

输出:3

解释:
在这里插入图片描述

示例 2:

输入:num = 4, Xpos = 1, Ypos = 2

输出:5

解释:
在这里插入图片描述

提示:

  • 1 <= num <= 10^9
  • 0 <= Xpos, Ypos < num

思路1,超时

        问题就一句话, 给定坐标和阶数 求螺旋数组中对应下标的值。 我最开始的是直接模拟法,代码如下,具体思路可看 旋转矩阵的构造和螺旋三角阵的构造,能过测试用例,but 超时,哈哈哈哈,所以这就不细讲了

class Solution {
public:
    int orchestraLayout(int num, int xPos, int yPos) {
        int row=num,column=num;
        int max =1;
        int l = 0, r=column-1, u = 0, d=row-1;
        while (1) {
            for (int i = l; (i <= r) && (max > 0); i++) {
                if(u==xPos && i==yPos){
                    return max;
                }
                max++;
                if(max>9){max=1;}
            }
            u++;
            for (int i = u; (i <= d) && (max > 0); i++) {
                if(i==xPos && r==yPos){
                    return max;
                }
                max++;
                if(max>9){max=1;}
            }
            r--;
            for (int i = r; (i >= l) && (max > 0); i--) {
                if(d==xPos && i==yPos){
                    return max;
                }
                max++;
                if(max>9){max=1;}
            }
            d--;
            for (int i = d; (i >= u) && (max > 0); i--) {
                if(i==xPos && l==yPos){
                    return max;
                }
                max++;
                if(max>9){max=1;}
            }
            l++;
        }
         return max;
};

思路2 找规律

        所以显然要找规律,那规律是啥呢?因为元素是一圈一圈填充进去的,每一圈的长也是和圈数有关系的,

在这里插入图片描述

  • 所以我们可以先计算出来坐标在哪一圈,怎么计算呢,最简单的想法,xPos yPos里面谁比较小就是,但是我们再先想想,一圈要占两行两列,所以还要考虑 row-xPos 和 col-yPos,所以综上就是这四个谁小就是在那一圈,我们是方阵,所以 行和列最大下标都是 num-1
key = min(min(xPos,num-1-xPos),min(yPos,num-1-yPos))
  • 有了圈数然后呢?有了圈数就可以算这圈之前填了多少数字,第 key 圈的边长是 size=num-2*key,那么一圈的个数就是 4*(size-1)=4*(num-2*key -1)= 4*(num-1) - 4*2*key
  • 其中4*(num-1) 是固定的, 4*2*key 是一个等差数列,那么算这圈之前填了多少数字就是一个等差数列求和的问题。
  • 已知数列的通项公式为 f(key)=(4*(num-1) - 4*2*key) key=[0, n] 其中 num 已知 ,求 Sn(key-1)
  • 带入求和公式 ((首项+末项)*项数)/2 得到 (4*(num-1)+(4*(num-1) - 8*key-8))*key/2 注意,项数是 [0,key-1] ,一共有 key 项,然后化简得 4*(num-1)*key - 4*(key-1)*key
long long ret=0;
if (key>0){
	ret+=(num-1)*key*4;
	ret-=4*(key-1)*key;
}
  • 计算完前面有多少个数字后,又该咋整呢,接着我们就看这个坐标究竟落在第 key 圈得上下左右那一条边上,然后就知道了具体数值了
class Solution
{
public:
    int orchestraLayout(int num, int xPos, int yPos) 
	{
		long long key=min(min(xPos,num-1-xPos),min(yPos,num-1-yPos));
		long long ret=0;
		long long size=num-key-key;
		if (key>0){
			ret+=(num-1)*key*4;
			ret-=4*(key-1)*key;
		}
		//把key圈提出来当成一个新的方阵,方便计算 往左上方平移key个位置
		xPos -= key;
		yPos -= key;
		
		if (xPos==0)   //在上面一条边上,那就看看往右得y走了几个位置 +上去
			ret+=yPos;
		else if (yPos==size-1) //在右边一条边上,加上一条边的个数(size-1) 再看看往下走了几个位置 +上去
			ret+=size-1+xPos;
		else if (xPos==size-1)  //在下面一条边上,加上两条边的个数   2 *(size-1) 再看看往右走了几个位置 +上去
			ret+=(size-1)*2+(size-1-yPos);
		else  //在左面一条边上,加上三条边的个数   3 *(size-1) 再看看往上走了几个位置 +上去
			ret+=(size-1)*3+(size-1-xPos);
		return ret%9+1;   //为什么+1是因为我们计算ret 的时候是从0开始的
	}
};

如果好理解上面为什么要平移,也可以试着理解这个

class Solution {
public:
    int orchestraLayout(int num, int xPos, int yPos) {
        long long key=min(min(xPos,num-1-xPos),min(yPos,num-1-yPos));
		long long ret=0;
		if (key>0){
			ret+=(num-1)*key*4;
			ret-=4*(key-1)*key;
		}
		// xPos -= key;
		// yPos -= key;
		long long size=num-key-key;
		if (xPos==key)   //刚好在 第key圈的上面一条边
			ret+=yPos-key;   //第key圈,所以移动的时候要减掉之前的圈的个数
		else if (yPos==num-1-key)
			ret+=size-1+xPos-key;
		else if (xPos==num-1-key)
			ret+=(size-1)*2+(num-1-yPos-key);
		else
			ret+=(size-1)*3+(num-1-xPos-key);
		return ret%9+1;  
    }
};
posted on 2021-06-06 18:32  雾恋过往  阅读(65)  评论(0编辑  收藏  举报

Live2D