티스토리 뷰

Algorithm

[JS] [Programmers] 삼각 달팽이

김관장 2022. 6. 17. 18:05
 

코딩테스트 연습 - 삼각 달팽이

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

programmers.co.kr

  • 프로그래머스 코딩테스트 연습 월간 코드 챌린지 시즌1 Level 2 문제입니다.

 

나의 풀이


function solution(n) {

    let answer = Array.from({ length: n }, (dr, idx) => [...'0'.repeat(idx + 1)]); // 배열 초기화
    let curIdx = [0, 0]; // 탐색을 시작할 인덱스
    let inputNum = 1; // 들어갈 숫자

    for (let i = 1; i <= n; i++) {

        let mod = i % 3; // 3으로 나눈 나머지에 따라 값을 넣어주는 로직이 달라짐
        let row = curIdx[0]; // 현재 인덱스의 row(행)
        let col = curIdx[1]; // 현재 인덱스의 col(열)

        if (mod == 1) {
        
            while (answer[row]) {
                if (answer[row][col] == '0') {
                    answer[row++][col] = inputNum++;
                } else {
                    break;
                }
            }
            row -= 1;
            col += 1;
            
        }
        else if (mod == 2) {
        
            while (answer[row][col]) {
                if (answer[row][col] == '0') {
                    answer[row][col++] = inputNum++;
                } else {
                    break;
                }
            }
            row -= 1;
            col -= 2;
            
        }
        else {
   
            while (answer[row]) {
                if (answer[row][col] == '0') {
                    answer[row--][col--] = inputNum++;
                } else {
                    break;
                }
            }
            row += 2;
            col += 1;
            
        }

        // 탐색을 시작할 인덱스 값을 바꿔줌
        curIdx = [row, col];
    }

    return answer.reduce((acc, cur) => [...acc, ...cur]);
}

 

풀이 순서


  • mod 1인 경우 아래로 이동합니다. (파란색)

  • mod 2인 경우 동일 row의 우측으로 이동합니다. (주확색)

  • mod 3인 경우 위로 이동합니다. (노란색)

위 같은 규칙을 발견하고, 이를 코드화 해봤습니다. 

 

 

 

  1. 먼저 n길이 만큼의 배열을 '0'을 넣어 초기화합니다.

  2.  [ 1 ~ n ] 까지 반복하며, 그 값을 3으로 나누어 나온 나머지 값을 기준으로 각기 다른 로직으로 배열을 채워주도록 구현했습니다.

  3.  로직이 끝나면 탐색을 시작할 인덱스를 다음 탐색의 첫번째 위치로 설정해주도록 구현했습니다.

    1. mod 1인 경우 - 아래로 이동

      아래로 이동하기 때문에 row++ 해주며 탐색 진행, 반복문을 나오는 경우는 배열의 길이를 초과하거나 탐색한 위치에 값이 있는 경우이기 때문에 최종 row값에 -1을 해줘야하며 다음 탐색 시 현재 인덱스의 다음 열부터 탐색해줘야하므로 col 값에 +1을 해줍니다.
      결과적으로 row-=1, col+=1;

    2. mod 2인 경우 - 동일 row의 우측으로 이동

      동일 row의 우측으로 이동하기 때문에 col++ 해주며 탐색 진행, 반복문을 나오는 경우는 배열의 길이를 초과하거나 탐색한 위치에 값이 있는 경우이기 때문에 최종 col 값에 -1을 해줘야하며 다음 탐색 시 현재 인덱스의 윗줄의 마지막 col부터 탐색해줘야 하는데, 이는 즉 현재 인덱스의 row-=1, col-=1 한 위치와 같습니다.
      결과적으로 row-=1, col-=2;

    3. mod 3인 경우 - 위로 이동

      위로 이동하기 때문에 row--, col-- 해주며 탐색을 진행하고, 반복문을 나오는 경우는 탐색한 위치에 값이 있는 경우이기 때문에(앞선 mod 1, 2의 경우에서 mod 3탐색 위치에 값을 넣어주기 때문에 배열의 길이를 초과할 일은 없음) 최종 row 값과 col 값에 +1을 해줘야하며 다음 탐색 시 현재 인덱스의 아랫줄의 col부터 탐색을 해줘야하기 때문에 row+=1을 해줍니다.
      결과적으로 row+=2, col+=1;
  4. reduce() 함수를 사용하여 배열을 순차적으로 출력했습니다. 

 

다른 사람의 풀이


function solution(n) {
  let a = Array(n).fill().map((_, i) => Array(i + 1).fill())
  let row = -1
  let col = 0
  let fill = 0
  for (let i = n; i > 0; i -= 3) {
    a[++row][col] = ++fill
    for (let j = 0; j < i - 1; j++) a[++row][col] = ++fill
    for (let j = 0; j < i - 1; j++) a[row][++col] = ++fill
    for (let j = 0; j < i - 2; j++) a[--row][--col] = ++fill
  }
  return a.flat()
}
  • 3으로 나눈 나머지와 인덱스를 저장할 row,col을 이용하는 것은 똑같습니다.
  • 차이점

    • 나의 풀이

      [ 1 ~ n ] 까지 반복하며 수를 채워주고, 배열의 길이를 초과하거나 탐색 위치에 값이 있으면 탐색을 종료하고 다음 탐색할 위치를 재설정 해주는 방법

    • 다른사람의 풀이

      한 사이클 ( for (let i = n; i > 0; i -= 3) )씩 반복하며 수를 채워주고, 각 꼭대기값(즉 값이 겹치는 부분, 이부분까지 탐색하면 저처럼 탐색 위치를 직접 재설정해줘야합니다.)을 제외하고 반복하여, 탐색할 위치를 따로 재설정 해줄 필요가 없는 방법 또한 flat()함수를 이용하여 배열을 간단하게 이어붙임. 

      *flat() 모든 하위 배열 요소를 지정한 깊이까지 재귀적으로 이어붙인 새로운 배열을 생성

 

 

겹치는 부분을 제외하는 것이 탐색 인덱스를 따로 설정할 필요가 없어 더욱 간단하게 풀 수 있는 문제였다. 처음 풀 때 겹치는 부분을 제외하려는 생각은 했었지만 혹시나 탐색하지 못하는 부분이 있을까봐 또 인덱스 설정을 하기 까다롭다고 생각했기때문에 다른 방법을 택했는데, 앞으로는 시간을 더 들여서 효율적이고 간단하게 풀도록 노력해봐야겠다 ~
댓글