[Programmers/Lv. 2] 삼각 달팽이 (월간 코드 챌린지 시즌1, Python)

2023. 8. 15. 14:47Algorithm

📎 링크


 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

🤔 문제설명, 제한사항, 입출력 예


정수 n이 매개변수로 주어질 때, 그림과 같은 밑변의 길이와 높이가 n인 삼각형에 맨 위 꼭짓점부터 반시계 방향으로 달팽이 채우기를 진행한다.
첫 행부터 마지막 행까지 모두 순서대로 합친 새로운 배열을 구하라는 문제이다.

 

 

🤔 내가 생각한 풀이 과정


나는 아래와 같은 순서를 가지고 문제를 해결하려 했다.
값을 넣을 2차원 배열을 만든다. -> 배열에 들어가는 최댓값을 구한다.(n=4일 때 10, n=5일 때 15) -> 1부터 구한 최댓값까지 반복하면서 올바른 행, 열 위치에 따라 값을 넣어준다. -> 2차원 배열을 1차원 배열로 풀어주고, 반환한다.

1) 값을 넣을 2차원 배열과, 배열에 들어가는 최댓값을 구한다.
우선, 최종으로 반환할 배열은 answer라는 이름으로, 값을 넣을 2차원 배열은 graph로 각각 만들어줬다.
주어진 n에 따라 그려지는 삼각형의 길이와 높이가 달라지기 때문에, n번 반복하면서 삼각형의 모양을 2차원 배열의 형태로 만들었다. 
또한, 최댓값은 1부터 n까지 더한 합계로 나타나기 때문에 반복과 함께 더해 max_num을 만들어줬다.

2) 1부터 max_num까지 반복하면서 올바른 행, 열 위치에 따라 값을 넣어준다.
가장 어려웠던 부분이다.
일단, 조건을 늘리면 한없이 늘어날 수 있어서 몇 가지 방법(변수)을 고정하고 문제를 풀었다.
1. 값을 집어넣을 때는 행 인덱스 row와 열 인덱스 col을 이용해 올바른 위치에 넣어줄 것이고, 2차원 배열의 형식으로 만들어줬기 때문에 graph[row].insert(열 인덱스, 반복 값)의 형태로 넣어주는 양식을 고정했다.
2. 삼각 달팽이라는 문제에서 온 값을 넣는 방법은 3가지로 나눌 수 있었다. 위에서 아래로 값을 넣는 방향, 왼쪽에서 오른쪽으로 값을 넣는 방향, 아래에서 위로 값을 넣는 방향. 이 3가지의 방향을 arrow 변수의 0, 1, 2로 각각 조건을 나눠 만들었다.
3. 내가 이동할 수 있는 최대 거리(fill)와, 현재 이동한 거리(check_fill)를 나눠줬다.
문제를 보면, 계속 반시계 방향으로 이동한다는 점 때문에 이동하는 거리가 밑으로 4, 오른쪽으로 3, 위로 2, 밑으로 1.. 이런 식으로 반복되는 것을 확인할 수 있었다. 즉, 처음 이동할 수 있는 거리는 n에서부터 시작해 방향이 바뀔 때마다 1씩 줄어든다는 뜻이었고, 방향이 바뀔 때마다 최대거리는 1씩 줄이면서 이동한 거리는 0으로 초기화하는 코드를 반복해 줬다.


이 변수와 조건을 토대로 값을 넣을 행, 열의 인덱스와 변수의 초기화를 신경 써서 코드를 짜게 되었다.
각 조건별로 어떤 변수가 늘어나고, 초기화되고 하는 것은 코드의 주석으로 일일이 남겼으니 확인하면 되겠다 ㅠ (하나하나 쓰면 너무 길어져서ㅜ)

3) 2차원 배열을 하나의 1차원 배열로 풀어주고, 최종 값을 반환한다.
graph의 길이(len)만큼 행, 열에 따른 반복을 하면서, 최종 반환할 answer 리스트에 graph[i][j]의 형태로 append 해줬다.

 

 

👨‍💻 코드


def solution(n):
    answer = []
    graph = []
    max_num = 0     # 집어넣을 값의 범위
    
    # 그래프 세팅과, max_num값 구하는 반복문
    for i in range(n):
        graph.append([])
        max_num += i+1
        
    arrow = 0   # 화살표 방향 (0은 아래, 1은 오른쪽, 2는 위)
    
    row = 0     # 값을 넣을 행 인덱스
    col = 0     # 값을 넣을 열 인덱스

    fill = n        # 얼마나 이동해야하는지를 알려주는 카운트
    check_fill = 0  # 얼마나 이동했는지를 비교하는 카운트
        
    # max_num 만큼 반복하면서 리스트 위치에 따라 값을 넣어주기
    for i in range(max_num):
        
        # arrow 0: 밑으로 내려가면서 값을 채우는 화살표 방향
        if arrow == 0:
            graph[row].insert(col, i+1)   # 아래부터 순서대로 가장 앞에 넣기
            check_fill += 1               # 1 이동함     
            
            # 아직 내려갈 위치가 남은 경우
            if check_fill < fill:
                row += 1
                
            # 아래로 내려가서 가장 바닥을 찍은 경우
            elif check_fill == fill:    
                fill -= 1        # 이동해야 하는 범위는 1 마이너스.
                check_fill = 0   # 얼마 이동했는지를 알려주는 카운트는 다시 초기화
                arrow = 1        # 화살표 방향을 바꿈
                col += 1         # 오른쪽으로 한칸 이동해야함

        # arrow 1: 오른쪽으로 가면서 값을 채우는 화살표 방향
        elif arrow == 1:
            graph[row].insert(col+check_fill, i+1)    # 오른쪽순대로 값을 넣기
            check_fill += 1     # 1 이동함
            
            # 오른쪽으로 이동을 다 한 경우
            if check_fill == fill:
                fill -= 1       # 이동해야 하는 범위는 1 마이너스
                check_fill = 0  # 얼마 이동했는지를 알려주는 카운트는 다시 초기화
                row -= 1    # 위로 올라가야하므로, row를 1 줄인다.
                arrow = 2   # 화살표 방향을 바꿈

        # arrow 2: 위로 올라가면서 값을 채우는 화살표 방향
        elif arrow == 2:
            graph[row].insert(col, i+1)   # 위로 갈수록 값을 채우기
            check_fill += 1     # 1 이동함
            
            # 아직 올라갈 위치가 남은 경우
            if check_fill < fill:
                row -= 1
                
            # 위로 올라가서 가장 윗 부분을 찍은 경우
            elif check_fill == fill:
                fill -= 1       # 이동해야 하는 범위는 1 마이너스
                check_fill = 0  # 얼마 이동했는지를 알려주는 카운트는 다시 초기화
                row += 1    # 밑으로 내려가야하므로, row를 1 증가시켜준다.
                arrow = 0   # 화살표 방향을 바꿈
                
    # graph 리스트를 벗기고, 반환을 위한 하나의 answer 리스트에 새로 담는다
    for i in range(len(graph)):
        for j in range(len(graph[i])):
            answer.append(graph[i][j])

    return answer