[프로그래머스] 정수를 나선형으로 배치하기

LSA·2025년 4월 11일
0

javascript+a

목록 보기
9/10
post-thumbnail

문제 링크

문제 설명

양의 정수 n이 매개변수로 주어집니다. n × n 배열에 1부터 n2 까지 정수를 인덱스 [0][0]부터 시계방향 나선형으로 배치한 이차원 배열을 return 하는 solution 함수를 작성해 주세요.

입출력 예

nresult
4[ [1, 2, 3, 4], [12, 13, 14, 5], [11, 16, 15, 6], [10, 9, 8, 7] ]
5[ [1, 2, 3, 4, 5], [16, 17, 18, 19, 6], [15, 24, 25, 20, 7], [14, 23, 22, 21, 8], [13, 12, 11, 10, 9] ]

무슨 소리인가?

일단 문제 자체를 이해하지 못했다.저게 어떤 식으로 나선형이란 말인지? 생각했는데 다른 분이 주석으로 한번에 그려주신 것을 보고 바로 이해가 갔다. (출처: https://sefact.github.io/posts/181832/)

[0][0] → [0][1] → [0][2] → [0][3]  <<이건 인덱스 번호를 뜻함
                            ↓  ↓
[1][0] → [1][1] → [1][2]   [1][3]
 ↑  ↑              ↓  ↓     ↓  ↓
[2][0]   [2][1] ← [2][2]   [2][3]
 ↑  ↑                       ↓  ↓
[3][0] ← [3][1] ← [3][2] ← [3][3]

아...말 그대로 나선형으로 배치해야 한다는 말이군요?
물론 문제를 이해했다고 로직까지 한번에 생각할 수준은 되지 않는다.
몇 번을 반복문을 돌리며 시행착오를 하다가 하루 내로 풀지 못할것 같아 검색을 했다.

인터넷을 찾아보고 작성한 코드

function solution(n) {
    let array = new Array(n).fill().map(() => new Array(n).fill(0)),
    row = 0,
    col = 0,
    value = 1,
    direction = 'right';
    
    while(value <= n * n){ 
        array[row][col] = value++;
        
        if(direction == 'right'){
            if(col == n - 1 || array[row][col + 1] !== 0){
                direction = 'down';
                row++;
            }else{
                col++;
            }
        }
    
        else if(direction == 'down'){
            if(row == n - 1 || array[row + 1][col] !== 0){
                direction = 'left';
                col--;
            }else{
                row++;
            }
        }
    
        else if(direction == 'left'){
            if(col == 0 || array[row][col - 1] !== 0){
                direction = 'up';
                row--;
            }else{
                col--;
            }
        }
        
         else if(direction == 'up'){
             if(row == 0 || array[row - 1][col] !== 0 ){
                 direction = "right";
                 col++;
             }else{
                 row--;
             }
         }
    }

    return array;
}

코드 풀이

 let array = new Array(n).fill().map(() => new Array(n).fill(0)),
    row = 0,
    col = 0,
    value = 1,
    direction = 'right';
  • array
    어쨌든 리턴할 결과물은 배열이기 때문에 n의 개수만큼 0으로 채워진 배열을 생성한다.
    처음에 나는 new Array(n).fill([]) 과 같이 단순하게 처리했으나, 이렇게 되면 [[],[],[],[]]과 같이 빈 배열만 생성되므로 배열의 몇번째 인덱스인지 반복문에서 처리하지 못해 코드 자체가 돌아가지 않는다.그렇기 때문에 [[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]이와 같이 0으로 채워진 배열이라도 만들어 주는 것.

  • row , col
    각각 행, 열이 될 변수다. 부끄러운 이야기지만 나는 아직도 행과 열이 어디인지 계속 헷갈린다.
    행 : 세로로 읽는 y축 숫자
    열 : 가로로 읽는 x축 숫자

  • value
    각각의 배열에 들어가며 증가할 숫자다. 1에서 n * n까지라고 보면 되겠다.

  • direction
    방향을 나타낼 변수가 왜 필요하지? 생각했는데 의외로 많은 분들이 방향 변수를 추가하셨다. 아마 if문에서 판별하기 위해 사용하는 듯 싶다.

while(value <= n * n){  
  array[row][col] = value++;
  .
  .
  . 

처음 조건은 valuen * n 의 값을 가질때까지 반복문을 돌리는 것이다.
각 행/열마다 1씩 증가된 value 값을 넣어준다.

오른쪽으로 이동하기

 if(direction == 'right'){
            if(col == n - 1 || array[row][col + 1] !== 0){
                direction = 'down';
                row++;
            }else{
                col++;
            }
   }

오른쪽으로 한 칸씩 이동하며 row 혹은 col이 증가한다.

  • col == n - 1
    위 표를 기준으로 보면 n은 4이기 때문에 맨 마지막 열은 n - 1 이 될 수밖에 없다.그렇기 때문에 coln - 1 값과 같아지면 방향을 바꿔야 한다.
  • array[row][col + 1] !== 0
    예를 들어 위 표에서 array[0][2]에 들어가 있는건 3이라는 숫자다. 처음 시작할땐 col == n - 1 를 판별하는 과정에서 알아서 바뀌겠지만, array[1][0] 번째부터 다시 오른쪽으로 방향을 틀어 나가야 하기 때문에 이 조건이 필요하다. array[1][3]에는 이미 세로로 내려오면서 5라는 값이 들어가 있기 때문이다.
    때문에 위의 조건 둘 중 하나를 충족하면, 방향 변수가 'down'으로 바뀌고 행의 숫자가 증가해야 한다. 그 전까지는 열의 숫자만 증가하며 숫자를 채워준다.

아래로 이동하기

else if(direction == 'down'){
            if(row == n - 1 || array[row + 1][col] !== 0){
                direction = 'left';
                col--;
            }else{
                row++;
            }
        }

if가 아니라 else if문으로 처리한것에 주목하기. 한번의 반복때 상하좌우를 한꺼번에 판별해야 해서 쓰는 것 같다. 만약 if문으로만 처리했으면 순차적으로 처리가 되었을 것이다.
어쨌든 여기서도 하나의 분기를 통해 방향이 바뀐다.

  • row == n - 1
    마찬가지로 n이 4라고 하면, 행의 맨 마지막도 n - 1이다. 처음 아래로 이동할 때를 위한 빌드업 조건.
  • array[row + 1][col] !== 0
    2번째 아래쪽 이동을 위한 조건. array[2][3]에는 이미 왼쪽을 지나오며 8이라는 숫자가 있으니까 방향을 바꾼다.

왼쪽으로 이동하기

else if(direction == 'left'){
            if(col == 0 || array[row][col - 1] !== 0){
                direction = 'up';
                row--;
            }else{
                col--;
            }
        }
  • col == 0
    첫 왼쪽루트에선 열이 0과 같을때 방향을 바꾼다. array[0][n]은 무조건 첫 번째 열이니 그럴만도 하다.
  • array[row][col - 1] !== 0
    2번째 왼쪽 루트를 탈때를 위한 조건이다.array[0][2] 에는 위로 올라오면서 11이라는 숫자가 이미 있기 때문에 방향을 바꾼다.
    여기선 rowcol이 1씩 감소하는데, 이는 말 그대로 왼쪽/위쪽으로 이동하기 위해 n-1까지 증가한 값을 하나씩 빼주어야 하기 때문이다.

위쪽으로 이동하기

 else if(direction == 'up'){
             if(row == 0 || array[row - 1][col] !== 0 ){
                 direction = "right";
                 col++;
             }else{
                 row--;
             }
         }
  • row == 0
    array[n][0]이 되었을때 방향을 바꾼다.
  • array[row - 1][col] !== 0
    2번째 위쪽 루트를 탈 때를 위한 조건이다. 위의 왼쪽 조건에서 -1을 해주는 순서만 바뀌었다.
    대신 이제 위 > 오른쪽으로 방향을 바꿔야 하므로, 방향 변수가 right로 변경되며 열의 값은 +가 되어야 한다.

처음 위 코드를 보고 썼을때는 왜 이런 식으로 작성해야 하지?라며 의문이 가는 부분이 있었는데 역시 이해가 안 될때는 코드를 한줄씩 해석하며 이해하는게 도움이 되는 것 같다. 나중에는 다른 풀이방식도 해석해봐야겠다.

profile
진짜 간단하게 작성한 TIL 블로그

0개의 댓글