前言

从今天开始每日更新算法解题思路。

今天做了一道入门题(这真的是入门吗,花费了我快两个小时才解出答案。。)

题目链接

分析

首先我们先来看下输入和输出样例:

1
2
输入:
4
1
2
3
4
5
6
输出:

1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7

其实从样例来看并不是很难理解,它是按照一个特定的顺序进行递增的,总数为N^2,我们可以通过i++变量来实现这种效果,至于达到这个效果,我们可参考时钟的方向,因为时钟的方向和这个矩阵是有相同之处的,这个我也不好解释,仔细看看输出就能了然。

首先我们想到的肯定是用到二维数组,不然不能说不可能实现这种效果,而是很麻烦,而二维数组刚好实现了一个坐标系。

但是,这与我们经常见到的坐标系并不是很相似,为什么呢,因为我们常见的起点是左下角,而这个是左上角,所以说在这道题里x与y的方向会产生一些微妙的变化。具体来说,那就是x成为y,反之亦然。

代码

我们看下AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.util.Scanner;

/**
* Created By XuanRan on 2021/12/9
*/
public class P5731蛇形方针 {
public static int[][] mp = new int[100][100];
public static int N;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();

int K = 1;
int x = 1;
int y = 0;
while (K <= N * N){

while (mp[x][y + 1] == 0 && y < N) mp[x][++y] = K++;
while (mp[x + 1][y] == 0 && x < N) mp[++x][y] = K++;
while (mp[x][y - 1] == 0 && y > 1) mp[x][--y] = K++;
while (mp[x - 1][y] == 0 && x > 1) mp[--x][y] = K++;

// break;

/*while (mp[x][y] == 0 && y < N) mp[x][y++] = K++;
while (mp[x][y] == 0 && x < N) mp[x++][y] = K++;
while (mp[x][y] == 0 && y > 1) mp[x][y--] = K++;
while (mp[x][y] == 0 && x > q++) mp[x--][y] = K++;
print();

*/
}
print();

}

static void print(){
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
System.out.printf("%3d",mp[i][j]);
/* for (int k = 1; k <= getLen(mp[i][j]) + 1; k++) {
System.out.print(" ");
}
System.out.print(mp[i][j]);*/
}
System.out.println();
}
}
static int getLen(int x){
int ans = 0;
while (x / 10 != 0){
x /= 10;
ans++;
}
return ans;
}
}

里面有些遗留代码,但我没删,不需要注意那些多余的就好了。

代码中最重要的部分莫过于while循环了,因为是N * N的方阵,那么while循环正好也就限定了元素的个数。

循环中我又嵌套了四个循环,通过四个循环来分别实现向右、向下、向左、向上的转向。

在内循环中,我每次又使用类mp[x][y+1]的方式,这样做是为了检查下一个点是否已经遍历过,如果不这样用,while循环将会多执行一次,使得x或y的下标进行多一次的变化(可参考while循环中注释的代码,都是我的经验。。),进而影响到下次循环的位置。

详解

1
while (mp[x][y + 1] == 0 && y < N) mp[x][++y] = K++;

上面我已经说过了,在这个题中x和y是相反的,而在这段代码中,我们先检查x行的第y +1个元素是否访问过,并且检查y是否小于N,这步的主要目的在于防止下标越界,因为我们是N*N的矩阵,横向元素肯定不能大于N,然后我们对这个元素进行具体的赋值操作,其余三个都是换汤不换药,差不了多少。

  • 往下走时:y(横向)保持不变,x自增
  • 往左走时:y自减,x不变
  • 往上走时:y不变,x自减

结语

既然代码写完了,输出格式也得留意,它的要求是每个输出占三个字符位,不够则加空格,所以在输出时我们当然得检查下数字的大小对吧,这也就是getLen方法的来源,虽然没有写对,但是在写这个方法的时候我想到了另一个方法就是字符格式化加%3d,可以正好实现这个效果。