코딩테스트

프로그래머스 - 삼각 달팽이 (레벨2, swift)

momo_9 2020. 12. 18. 22:27

문제 출처

programmers.co.kr/learn/courses/30/lessons/68645

 

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

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

문제 설명

정수 n이 매개변수로 주어집니다. 다음 그림과 같이 밑변의 길이와 높이가 n인 삼각형에서 맨 위 꼭짓점부터 반시계 방향으로 달팽이 채우기를 진행한 후, 첫 행부터 마지막 행까지 모두 순서대로 합친 새로운 배열을 return 하도록 solution 함수를 완성해주세요.

제한 사항

    -  n은 1 이상 1,000 이하입니다.

 

입출력 예

n result
4 [1,2,9,3,10,8,4,5,6,7]
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]

 

 

 

✨문제풀이

어렵고 어려웠다ㅠㅠ...

특히 이 문제를 풀때는 뭔가 다 귀찮아서 생각하고 머리쓰는 걸 하기가 너무 싫었다. 그래서 계속 안되면 왜 안되는지 코드를 처음부터 훑어보면서 고민해봐야 하는데 대충 처음에 생각난대로 어거지로 풀려다가...근데 또 찾아보는 건 싫고..그래서 더 오래 걸린듯하다. 풀고 나니까 그렇게 어려운 문제는 아니였던 거 같은데 처음 하려던 방법으로는 값 한 두개가 계속 틀려서 엄청 삽질하다 결국 다른 방법으로 풀었다. 풀면서 남들은 어떻게 풀었나 나 이렇게 막 풀어도 되나...궁금했는데 막상 풀고 나니까 지긋지긋해서 다른 사람들 코드를 보지 못했다. 이거 작성하고 나면 한번 다시 찾아봐야 겠다.

 

달팽이 모양처럼 반시계방향 순으로 숫자를 차례대로 채우면 되는 문제이다.

 

아래와 같이 아래 방향, 오른쪽 방향, 위 방향 이렇게 3가지로 나누어 각 방향에 따라 순서대로 값이 채워지게 하였다. 

n이 6일경우, 각 방향 당 처음엔 n-1인 5개씩, 두번째엔 n-3인 2개씩 값이 채워진다. 

n = 4일 경우 3, 1

n = 5일 경우 4, 1

n = 6일 경우 5, 2 (노란색 5개, 빨간색 2개)

n = 7일 경우 6, 3, 1

n = 8일 경우 7, 4, 1 개의 숫자들이 순서대로 채워진다. n-1로 시작해 -3씩 작아지는 데 만약 -3을 한 값이 0이라면 1로 바꿔주면 된다.

이걸 이용해서 반복문의 횟수를 조정하면 된다.

 

 1) 먼저 enum을 사용해서 방향으로 지정할 값을 한정해주었다. 

각 방향을 down, right, up 으로 설정해줬다.

 

  enum Direction {

    case down

    case right

    case up

  }

 

 

2) 그림과 똑같은 형태의 이중 배열을 만들고 0으로 초기화해 주었다.

 sum 변수를 만들어 채워질 숫자의 총 개수를 구해준다.

 

  for i in 0..<n {

    array.append([Int](repeating: 0, count: i+1))

    sum += i + 1

  }

 

 

 3) while과 switch문을 이용해  count가 sum만큼 커질때까지 반복문을 실행시킨다.

 

repeat {

    switch direction {

    case.down:

      direction = .right

    case .right:

      direction = .up

    case .up:

      direction = .down

    }

  } while count <= sum 

 direction변수를 만들어 방향을 지정해 주었고 switch 문에서 현재 방향에 맞는 실행문이 실행되도록 하였다. 각 실행문이 끝나면 다음 진행방향이 설정되도록 해주었고 반복문에 의해 계속적으로 다음 진행방향에 맞는 실행문이 실행되며 달팽이 채우기가 진행되도록 하였다.

 

 

 4) down방향에서는 각 행의 똑같은 열에 값이 순서대로 저장되도록 했다.

 

     for i in 0..<oneline {

        array[i+(value*2)][value] = count

        count += 1

      }

  여기서 열에 해당하는 index는 고정되므로 for문으로 증가하는 값은 행에 해당하는 index 변화에 맞춰줘야 한다. n이 6일 경우 첫번째 바퀴에서 oneline = 5, index는 [0,0] [1,0] [2,0] [3,0] [4,0]이 되고 두번째 바퀴의 oneline= 2, index는 [2,1] [3,1] 이 된다. 그리고 만약에 n이 6보다 커서 두바퀴 이상 돌 경우 세번째 바퀴의 index는 [4,2] 부터 시작하게 된다. 행은 각각 0, 2, 4부터 시작해서 1씩 더해지는 것을 알 수 있다. 따라서 위와 같이 for문을 구현하면 된다. 여기서 value변수는 한 바퀴 돌때마다 한 진행방향 당 채워지는 칸 수가 줄어드는 만큼 변화되는 index를 조정하기 위한 값이다. oneline은 각 방향마다 값을 채울 개수를 저장하는 변수이다. 한 바퀴 돌때마다 -3씩 작아진다.

 

   direction = .right

 모든 값이 저장되면 진행방향을 right로 바꿔준다.

 

 

 5) right방향에서는 같은 행 다른 열에 값이 순서대로 저장되도록 했다.

   

     for i in 0..<oneline {

        array[n-1-value][i+value] = count

        count += 1

      }

 여기에선 행이 고정되어있고 열이 하나씩 커지므로 for문으로 증가하는 값은 열에 해당하는 index 변화에 맞춰줘야 한다. n이 6일 경우 첫번째 바퀴에서 oneline = 5, index는 [5,0] [5,1] [5,2] [5,3] [5,4]이 되고 두번째 바퀴에서 oneline = 2, index는 [4,1] [4,2] 이 된다. 그리고 만약에 n이 6보다 커서 두바퀴 이상 돌게 될 경우 세번째 바퀴의 index는 [3,2]부터 시작하게 된다. 행은 가장 마지막 행부터 1바퀴씩 돌때마다 -1씩 작아지고 열은 0부터 시작해서 1씩 커지는데 1바퀴씩 돌때마다 1씩 커진 index로 시작하게 된다. 따라서 위와같이 for문을 구현하면 된다.

 

 direction = .up

 모든 값이 저장되면 진행방향은 up으로 바꿔준다. 

 

 

 6) up방향에서는 같은 열 다른 행에 역순으로 값이 저장되도록 했다. 

 

     for i in value..<oneline+value {

        array[n-1-i][n-1-i-value] = count

        count += 1

      }

  여기에선 down처럼 열이 고정되고 행이 달라지는 것은 같지만 행의 순서가 역순으로 진행된다는 것이 다르다. n이 6일 경우 첫번째 바퀴에서 oneline = 5, index는 [5,5] [4,4] [3,3] [2,2] [1,1]이 되고 두번째 바퀴에서 oneline = 2, index는 [4,3] [3,2]가 되고 만약 n이 6보다 커서 두바퀴 이상 될게 될 경우 세번째 바퀴의 index는 [3,2]부터 시작하게 된다. 행과 열이 모두 1씩 작아지고 1바퀴씩 돌때마다 이전보다 행과 열이 1씩 작아진 상태에서 시작되는 것을 볼 수 있다. 따라서 for문으로 증가하는 값이 행과 열에 해당하는 index 변화에 맞춰주도록 해야 한다. 난 위와 같이 구현해주었다.

     

     direction = .down

     oneline = oneline - 3 == 0 ? 1 : oneline - 3

     value += 1

 모든 값이 저장되면 진행방향은 down으로 바꿔준다. 이렇게 순서대로 down, right, up까지 한번씩 값을 채워주면 한 바퀴가 돌게 되는데 value변수는 +1을 해주고,  oneline 또한 이 시점에 -3을 해준다. 

 

 

전체 코드는 아래와 같다.