4 minute read


문제


아래 와 같은 형태로 데이터를 저장하는 이차원 배열을 생성하세요.



문제 풀이


주어진 문제 보기와 같이 달팽이 모양의 2차원 배열을 만들어야 한다.
여기서 배열을 잘 살펴보면, 안쪽으로 말려 들어가는 달팽이 집과 같은 모양을 보이고 있음을 알 수 있다.

이 원리를 코드로 구현하기 위한 아이디어를 생각해보자.


아이디어 도출

정사각형 형태의 배열이기에 가로 열과 세로 행은 같다고 보고, 2차원 배열 안에 채워지는 숫자를 어떻게 채워갈지 정해보자.

  1. 1부터 5까지는 첫번째 행에 오른쪽으로 채워지며 5부터 9까지는 5번째 열에 아래로 채워진다.
  2. 10부터 13까지는 5번째 행에서 왼쪽으로 채워지며, 13부터 16까지는 1번째 열에서 위로 채워진다.
  3. 16부터 19까지는 2번째 행에서 오른쪽으로 채워지며, 19부터 21까지는 4번째 열에서 아래로 채워진다.
  4. 21부터 23까지는 4번째 행에서 왼쪽으로 채워지며, 23부터 24까지는 2번째 열에서 위로 채워진다.
  5. 마지막으로 24에서 25로 3번째 행에서 채워지게 된다.

여기서 총 5번의 과정을 통해 1부터 25까지 달팽이 모양으로 2차원 배열을 채우게 되는데 이 5번이라는 것은 정사각형의 행, 열과 동일한 숫자임을 알 수 있다.

이 때, 5번 만큼 배열을 채울 때 일반적인 배열의 순서대로 오른쪽이나 아래로 채워지는 경우와, 배열의 순서와는 반대인 왼쪽이나 위로 채워지는 경우를 분기하여 채우도록 하면 된다. 그리고 채워질 수는 계속해서 증가시키며 행*열만큼의 수가 되도록 하면 된다.

오른쪽이나 아래로 채워지는 경우

1번 과정과 같이 원래 순서대로 자연스럽게 채워야 하는 경우를 살펴보자.
먼저 열에 값을 오른쪽 방향으로 채운 뒤, 행에 값을 아래 방향으로 아래와 같이 채우게 된다.

i가 행 인덱스, j가 열 인덱스라고 한다면 i는 0행으로 고정시키고, j만 1씩 증가시켜서 1~5까지 첫 행을 채워주어야 한다.
그리고 첫 행 채우기가 끝나면 열 인덱스 j를 고정시키고, i만 1씩 증가하며 채워주어야 한다.
단, 첫 열을 채울 때는 5-1번만큼 반복하여 6부터 9까지만 채우면 된다는 점을 유의해야 한다.

왼쪽이나 위로 채워지는 경우

1번 과정대로 배열을 채웠다면 10부터 13까지, 14부터 16까지는 반대 방향으로 배열을 채워야 한다.
이 때는 열 인덱스인 j를 1씩 감소시켜서 채워야 하기 때문에 방향을 반대로 바꿔줄 변수가 하나 있어야 한다.


문제 예시처럼 가로 5, 세로 5 크기를 가지는 정사각형을 채우려면 위 과정을 5번 반복하여 달팽이 배열을 채울 수 있게 된다.
아이디어가 생각보다 복잡해보이지만 필자가 장황하게 늘어놓은 점도 없지 않기에 코드를 작성하면서 이해하는 것이 더 쉬울 수 있다.

자 그럼 이제 코드를 작성해보자.

1
2
3
4
5
6
int[][] answer = new int[col][row];
int i = 0 // row start index
int j = -1; // col start index
int tmp = 0; // snail number
int direction = 1; // i with j switch direction(1 or -1)
int repeat = row; // repeat count

달팽이 모양대로 채워줄 2차원 배열 answr를 선언한다. 그리고 i는 행 인덱스, j는 열 인덱스를 의미하고 tmp는 각 배열에 채워줄 숫자 값이 된다.

j가 -1부터 시작하는 이유는, 행을 고정하고 열을 증가시키며 배열에 채워줄 때 배열의 범위를 벗어나지 않도록 하기 위함이다.

direction 변수는 방향이 바뀔 시 사용될 스위치 변수이며, repeat는 몇 번을 반복해야 하는지를 알려주는 반복 인덱스라고 보면 된다.

여기서는 정사각형이기 때문에 행과 열의 크기가 같기에 둘 중 아무거나 repeat로 선언해도 무방하다.

1
2
3
while(repeat > 0) {
    ...
}

기본적으로 repeat가 0이 될 때까지 반복하면 된다. 문제 예시대로라면 5번을 반복하게 된다.
while문에서 2차원 배열을 채우는 반복문을 작성해주면 되며, while문의 탈출 조건은 반복 인덱스인 repeat가 0과 작거나 같아지는 순간이다.

1
2
3
4
5
6
for(int l=0; l<repeat; l++) {
    tmp++;
    j = j + direction;
    answer[i][j] = tmp;
}
repeat--;

앞에서 구상한 아이디어대로 행 인덱스인 i를 고정해둔 채 j를 1씩 증가시키며 첫 행을 1부터 채워준다.
이 때, 열을 고정시키고 행을 증가시켜야 하는데 행의 첫번째 값은 이전에 채워졌으므로, 채워진 값 이후로 배열을 채우기 위해 repeat 변수를 1 감소시킨다.

1부터 5까지 5번을 반복하며 첫 행에 채워진다.

1
2
3
4
5
6
7
for(int m=0; m<repeat; m++) {
    tmp++;
    i = i + direction;
    answer[i][j] = tmp;
    
}
direction *= -1;

다음으로는 행 인덱스만 변경하며 배열을 채워주어야 하기 때문에 j를 고정해둔 채 행 인덱스인 i를 1씩 증가시키며 열 값을 채워준다.

6부터 9까지 4번을 반복하며 마지막 열에 채워진다.

이제 다시 배열의 행부터 값을 채워야 하는데 왼쪽이나 위 방향인 반대로 채워야 하기 때문에 열 인덱스인 j를 1씩 감소시켜야 한다. 그래서 선언해둔 스위치 변수인 direction을 -1로 바꾸어주면 된다.


이렇게 while문 안에서 두가지의 반복 과정을 진행하며 repeat 반복 변수가 0 이하가 된다면 while문을 종료된다.



작성 코드


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
import java.util.*;
class Solution {
    public int[][] solution(int row, int col) {
        
        int[][] answer = new int[col][row];
        int i = 0; // row start index
        int j = -1; // col start index
        int tmp = 0; // snail number
        int direction = 1; // i with j switch direction(1 or -1)
        int repeat = row; // repeat count

        while(repeat > 0) {
            for(int l=0; l<repeat; l++) {
                tmp++;
                j = j + direction;
                answer[i][j] = tmp;
            }
            repeat--;
            for(int m=0; m<repeat; m++) {
                tmp++;
                i = i + direction;
                answer[i][j] = tmp;
                
            }
            direction *= -1;
        }

        for(int[] arr : answer) {
            System.out.println(Arrays.toString(arr));
        }
        return answer;
    }
    public static void main(String[] args){
        Solution sol = new Solution();
        int row = 5;
        int col = 5;
        sol.solution(row, col);
    }
}

회고

  • 행과 열을 탐색하는 순서를 전환하기 위해 양수와 음수를 이용할 수 있었고, 열을 고정시키고 행을 1씩 증가시켜서 열 값을 채워주고 행을 고정시키고 열 값을 1씩 증가시켜서 행 값을 채워줄 수 있었다.