思路
我们可以先计算出目标点向外一共有多少圈,然后再分别讨论目标点在当前圈的上、右、下、左四种情况下的取值。
1.计算圈数
目标点有可能落在所在圈的上、右、下、左四个方向,如何根据其下标$(x,y)$来确定其在第几圈?
可以分别计算目标点到四个最外层边界的距离,最短的距离即为圈数。
2.计算外圈的长度
不难注意到,边长为$a$的圈长度为$4a - 4$,向内一圈的边长为$a - 2$,长度为$4(a-2) - 4 = 4a - 12$。所以是一个首项为$4a - 4$,公差为$-8$的等差数列。利用等差数列求和公式$S_n = a_1n + n(n-1)d/2$即可求出外圈总长度(其中$n$为项数)。
注意:由于数据范围为$10^9$, 直接使用求和公式会爆long long
,需要进行等价变形
3.分类讨论目标点落在所在圈的哪个方向
不妨令所在圈四个边界的坐标为left, right, up, down
- 如果在上方,则只需要加1段,即从左上角出发,向右走$y - left + 1$的距离;
- 如果在右方,则需要加2段,即从左上角出发,向右走$right - left$的距离,再向下走$x - up + 1$;
- 如果在下方,则需要加3段,即从左上角出发,向右走到底,再向下走到底,一共走$2(right - left)$,再向左走$right - y + 1$;
- 如果在左方,则需要加4段,即从左上角出发,向右走到底,再向下走到底,再向左走到底,一共走$3(right - left)$,再向上走$down - x + 1$.
参考代码
class Solution {
public:
int orchestraLayout(int n, int x, int y) {
long long layer = min(min(x, y), min(n - x - 1, n - y - 1)); // layer表示圈数,n为正方形的边长
// 下面这2行是等差数列求和公式的变形,为了防爆long long
long long len = layer * (n - 1) - (layer - 1) * layer;
len <<= 2;
long long up = layer, down = n - layer - 1;
long long left = layer, right = n - layer - 1;
if (x == up) len += y - left + 1;
else if (y == right) len += (right - left) + (x - up + 1);
else if (x == down) len += (right - left) * 2 + (right - y + 1);
else if (y == left) len += (right - left) * 3 + (down - x + 1);
return len % 9 == 0 ? 9 : len % 9;
}
};
感觉down应该是n-layer+1,right也是这个。另外最后一步讲解和代码不一致,应该是right-left。膜拜大佬
下标是从0开始,
down
表示目标点所在圈的下界的x
轴坐标,这里应该是没问题,可以把题目那几个样例代进去试试; 后面那里已改正,感谢。对对,层数和坐标都是从零开始。我都按一想的
给个题解修改建议,题解中等差数据的n和矩阵的n不是一个n,容易引起歧义,建议lz修改一下
已标注。
竟然算出了走了多少步,当时为啥我就没有想清楚?lz讲的真好
这题确实比较考验耐心hhh,比赛的时候一紧张就容易想错,很正常😂
计算外圈的长度还可以用面积法: 外面的大正方形面积 - 里面的小正方形面积
妙啊~~~👍
我跟你思路一样, 面积法是我看到别人的题解的.
求长度用面积法, 不太容易想到.
好!