题目描述
一个 n n n 行 n n n 列的螺旋矩阵可由如下方法生成:
从矩阵的左上角(第 1 1 1 行第 1 1 1 列)出发,初始时向右移动;如果前方是未曾经过的格子,则继续前进,否则右转;重复上述操作直至经过矩阵中所有格子。根据经过顺序,在格子中依次填入 1 , 2 , 3 , . . . , n 2 1, 2, 3, ... , n^2 1,2,3,...,n2,便构成了一个螺旋矩阵。
下图是一个 n = 4 n = 4 n=4 时的螺旋矩阵。1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7
现给出矩阵大小 n n n 以及 i i i 和 j j j,请你求出该矩阵中第 i i i 行第 j j j 列的数是多少。
输入格式
共一行,包含三个整数 n n n, i i i, j j j,每两个整数之间用一个空格隔开,分别表示矩阵大小、待求的数所在的行号和列号。
输出格式
一个整数,表示相应矩阵中第 i i i 行第 j j j 列的数。
样例输入
4 2 3
样例输出
14
数据范围
对于 50 % 50\% 50% 的数据, 1 ⩽ n ⩽ 100 1 \leqslant n \leqslant 100 1⩽n⩽100;
对于 100 % 100\% 100% 的数据, 1 ⩽ n ⩽ 30 , 000 , 1 ⩽ i ⩽ n , 1 ⩽ j ⩽ n 1 \leqslant n \leqslant 30,000,1 \leqslant i \leqslant n,1 \leqslant j \leqslant n 1⩽n⩽30,000,1⩽i⩽n,1⩽j⩽n。
思路
- 枚举每一圈,从而确定出题目要求的数在第几圈
- 每一圈的左上角的第一个数的是其外面所有圈的元素的个数(因为sum初始化为1)
- 计算该圈外面圈元素的个数类似于下图
public static void main(String[] args) throws IOException {
int n = readInt(), p = readInt(), q = readInt(), sum = 1, r = -1;
//当 n为偶数时,矩阵有 n/2圈;当 n为奇数时,矩阵有 n/2+1圈, 即总共有 n/2+n%2圈
//从第二圈开始枚举, 这样有利于计算, k表示上一圈是第几圈
for (int x1 = 2, y1 = 2, x2 = n - 1, y2 = n - 1, k = 1; x1 <= n/2 + n%2; x1++,y1++,x2--,y2--,k++) {
//出现在上一圈
if (p < x1 || p > x2 || q < y1 || q > y2) {
r = k; break;
}
//上一圈元素的个数
sum += ((x2 + 1) - (x1 - 1) + 1) * ((y2 + 1) - (y1 - 1) + 1) - (x2 - x1 + 1) * (y2 - y1 + 1);
}
if (r == -1) {//此时在最后一圈(最里面)
r = n / 2 + n % 2;
}
int i = r, j = r, d = 0;//i, j从当前圈的左上角开始遍历
int[] dx = new int[] {0, 1, 0, -1}, dy = new int[] {1, 0, -1, 0};//右下左上
while (true) {
if (i == p && j == q) {//遇到目标点
printWriter.println(sum);
break;
}
int nx = i + dx[d], ny = j + dy[d];
if (nx > n - r + 1 || nx < r || ny > n - r + 1 || ny < r) {//越界换位置
d = (d + 1) % 4;
nx = i + dx[d]; ny = j + dy[d];
}
i = nx; j = ny;
sum++;//因为从左上角开始遍历,所以每遍历一个元素就+1
}
}
考点:1. 计算当前处于第几圈 2. 计算外圈元素的个数 3. 圈内元素的遍历