프로그래머스 파이썬 기초 트레이닝 :: 정수를 나선형으로 배치하기 (*)

 



  

          


문제 설명 

프로그래머스 URL

https://school.programmers.co.kr/learn/courses/30/lessons/181832



프로그래머스 코딩 카테고리 

코딩 기초 트레이닝

Day 25 - 정수를 나선형으로 배치하기 

Lv.0



문제 내용 

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




넘나 어려운 문제다.. 




-----------------------------------


나선형으로 도는거기 때문에, 시계방향으로 돈다. 

방향은    U 이렇게 고정이 되어있다. 


4가지 경우에 따른 방향 설정

dir = R(1) → D(2) → L(3) → U(4)

def solution(n):
    answer = [[0]*n for i in range(n)]
    x, y = 0, 0
    
    dir = 'r'		#dir로 방향조정 : r, d, l, u
    
    if n == 1:
        return [[1]]
    
    for i in range(1, n*n+1):
        answer[x][y] = i 
        if dir == 'r':
            y += 1
            if y == n-1 or answer[x][y+1] != 0:
                dir = 'd'
        elif dir == 'd':
            x += 1
            if x == n-1 or answer[x+1][y] != 0:
                dir = 'l'
        elif dir == 'l':
            y -= 1
            if y == 0 or answer[x][y-1] != 0:
                dir = 'u'
        elif dir == 'u':
            x -= 1
            if x == n-1 or answer[x-1][y] != 0:
                dir = 'r'
                
    return answer


1) 1 X 1 배열일때  

if n == 1:
    return [[1]]

n이 1일때를 따로 지정해주지 않으면 테스트13에서 "실패 (런타임 에러)"로 뜸

그 이유는 x, y = 0, 0으로 선언하면 반복문을 시작한 r 방향때 부터 문제가 생긴다.


if dir == 'r':
    y += 1
    if y == n-1 or answer[x][y+1] != 0:
        dir = 'd'

y+=1 을 하는데 arr[0][0]을 입력하지않고, 바로 arr[0][1] 값부터 넣는데, 

y+=1 을 수행한 이후기 때문에 if y ==n-1 이 항상 참이 되기 때문이다. 

그래서 arr[0][0] 이 입력되지도 않아도 r 방향의 if문이 참이 되서 런타임 에러뜸  



2) r : 행은 그대로고, 열만 오른쪽으로 이동  

for i in range(1, n*n+1):
    answer[x][y] = i 

    if dir == 'r':
        y += 1
        if y == n-1 or answer[x][y+1] != 0:
            ir = 'd'

행은 그대로이기 때문에 answer[x][y] 에서 x축은 그대로고, y축만 +1 씩 이동 

이동한 y축이 배열의 끝까지 도착했을때나, 이미 answer 다음자리에 값이 들어가있으면 방향전환


3) d : 열은 그대로고, 행만 위에서 아래로 이동  

elif dir == 'd':
    x += 1
    if x == n-1 or answer[x+1][y] != 0:
        dir = 'l'

열은 그대로이기 때문에 answer[x][y] 에서 y축은 그대로고, x축만 +1 씩 이동 

동작이 멈추는 원리는 r때랑 동일


4) l : 행은 그대로고, 열만 오른쪽에서 왼쪽으로 이동  

elif dir == 'l':
    y -= 1
    if y == 0 or answer[x][y-1] != 0:
        dir = 'u'

행은 그대로이기 때문에 answer[x][y] 에서 x축은 그대로고, y축만 -1 씩 이동 


5) u : 열은 그대로고, 행만 밑에서 위로 이동  

elif dir == 'u':
    x -= 1
    if x == 0 or answer[x-1][y] != 0:
        dir = 'r'

열은 그대로이기 때문에 answer[x][y] 에서 y축은 그대로고, x축만 -1 씩 이동 




방향전환을 숫자로 지정해도됨 (원리는 동일) 

def solution(n):
    arr = [[0]*n for i in range(n)]
    x, y = 0, 0 

    mode = 1	#mode로 방향조정 : R(1)-> D(2) -> L(3) -> U(4)
    
    if n == 1:
        return [[1]]
    
    for i in range(1, n*n+1):
        arr[x][y] = i
        if mode%4 == 1:
            y+=1
            if y == n-1 or arr[x][y+1] != 0:		
                mode+=1
        elif mode%4 == 2:
            x+=1
            if x == n-1 or arr[x+1][y] != 0:
                mode+=1
        elif mode%4 == 3:
            y-=1
            if y == n-1 or arr[x][y-1] != 0:
                mode+=1
        elif mode%4 == 0:
            x-=1
            if x == n-1 or arr[x-1][y] != 0:
                mode+=1
    return arr



-----------------------------------


   U 순환하는건 고정이고, 과정마다 x축과 y축의 인덱스 변화를 표현하면 이렇다. 

x축은 R : 변화없음  D : +1씩 증가  L : 변화없음  U : -1씩 감소 

y축은 R : +1씩 증가  D : 변화없음  L : -1씩 감소  U : 변화없음 

이거를 배열로 표현하면 x축 = [0, 1, 0, -1], y축 = [1, 0, -1, 0]


x, y 축 배열을 설정 

x축 y축 배열을 활용해서 인덱스를 만듬  

def solution(n):
    answer = [[0]*n for _ in range(n)]
    dx=[0, 1, 0, -1]
    dy=[1, 0, -1, 0]
    x, y=0, 0
    answer[x][y] = 1
    k = 2
    while k <= n*n:
        for i in range(4):
            while True:
                nx = x + dx[i]
                ny = y + dy[i]
                
                if nx>=n or ny>=n or nx<0 or ny<0 or answer[nx][ny]!=0:
                    break
                else:
                    answer[nx][ny] = k
                    x = nx
                    y = ny
                    k += 1
    return answer


1) 1 X 1 배열일때  

dx=[0, 1, 0, -1]
dy=[1, 0, -1, 0]
x, y = 0, 0

이렇게 선언을 하고 반복문을 했을때 

제일 첫번째 수가 answer[0+0][1+0] 이렇게 되서, 이 코드 또한 answer[0][0]은 건너뛰기가 된다. 

  

answer[x][y]=1

그래서 answer[0][0] 값을 이렇게 지정해줘도된다. 



2) 세개의 반복문  

while k <= n*n:
    for i in range(4):
        while True:
            nx = x + dx[i]
            ny = y + dy[i]
                
            if nx>=n or ny>=n or nx<0 or ny<0 or answer[nx][ny]!=0:
                break
            else:
                answer[nx][ny] = k
                x = nx
                y = ny
                k += 1

① 반복문 : while k <= n*n:

k 값이 2부터 시작해 n*n 배열을 다 채울때까지 반복됨


② 반복문 : for i in range(4):

x축, y축 배열의 방향이 4개라서 4번 반복한다. 

우, 하, 좌, 상 순서로 이동하기 위한 방향을 나타낸다 


③ 반복문 : while True:

②의 for문에서 방향을 정했으면, 그 한쪽 방향으로 계속 이동하는 무한 루프이다. 

다음 배열 인덱스에 값이 이미 차있거나, 배열의 경계를 벗어날려고 하면 반복문을 종료하고 다음 방향으로 전환한다. 


while True:
    nx = x + dx[i]
    ny = y + dy[i]
                
    if nx>=n or ny>=n or nx<0 or ny<0 or answer[nx][ny]!=0:
        break
    else:
        answer[nx][ny] = k
        x = nx
        y = ny
        k += 1
if문으로 값이 이미 차있거나, 배열의 경계를 넘었을때 while True 문을 종료시키고 방향을 전환시킨다. 

else문에서는 인덱스 값에 k를 저장시킨다. 

다음 반복문이 돌때 x, y 값을 이어가기 위해서 x, y = nx, ny로 선언 



-----------------------------------



위의 코드에서는 while, for문을 사용해서 x축 y축 배열의 인덱스를 옮겨갔는데 

반복문 대신 dir의 숫자를 활용해서 인덱스에 접근을 할 수 있다. 

x, y 축 배열 인덱스를 활용

반복문을 최소화 할 수 있음   

def solution(n):
    dx = [0, 1, 0, -1]
    dy = [1, 0, -1, 0]
    x, y = 0, -1

    arr = [[0] * n for _ in range(n)]
    k = 1
    dir = 0
    while k <= n**2:
        nx = x + dx[dir]
        ny = y + dy[dir]
        if 0 <= nx < n and 0 <= ny < n and not arr[nx][ny]:
            arr[nx][ny] = k
            k += 1
            x, y = nx, ny
        else:
            dir = (dir + 1) % 4

    return arr


1) 1 X 1 배열일때  

dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]
x, y = 0, -1

x, y = 0, -1 로 선언을 했기때문에 

answer[0+0][1-1] = answer[0][0] 값 부터 시작을 한다. 

그래서, 이렇게 x, y를 선언하면 별도로 answer[0][0]일때 값을 주지 않더라도 테스트 13에서 런타임 에러가 나지않음


while k <= n**2:
    nx = x + dx[dir]
    ny = y + dy[dir]
    if 0 <= nx < n and 0 <= ny < n and not arr[nx][ny]:
        arr[nx][ny] = k
        k += 1
        x, y = nx, ny
    else:
        dir = (dir + 1) % 4

dir = (dir + 1) % 4 로 방향을 전환하기때문에 방향을 전환해주는 for문 - range(4)가 필요없게된다. 

그리고, if문에서 0 <= nx < n and 0 <= ny < n and not arr[nx][ny] 배열 범위가 넘어가지 않고 값이 0일때를 조건문 걸어둘 수 있다.

같은 의미 : nx < n and ny < n and nx >= 0 and ny >= 0 and answer[nx][ny] == 0

훨씬 코드를 간결하게 쓸 수 있어진다.. 





-----------------------------------







이동을 하는 배열을 이차원 배열로 둬서, x축 y축을 하나의 배열에서 수행할 수도 있다. 

x, y 축 2차원 배열

x, y축을 나타내는 2차원 배열과 방향을 조절하는 m 변수  

def solution(n):
    answer = [[None for j in range(n)] for i in range(n)]
    move = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    x, y, m = 0, 0, 0
    for i in range(1, n**2 + 1):
        answer[x][y] = i  
        if x + move[m][0] >= n or y + move[m][1] >= n or answer[x + move[m][0]][y + move[m][1]]:
            m = (m + 1) % 4
        x = x + move[m][0]
        y = y + move[m][1] 
    return answer


answer[x][y]로 값부터 넣은 뒤에 

if문으로 배열 인덱스 범위, 배열 값 체크한 뒤에 방향을 전환한다. 

입력 가능한 상태면 move 2차원배열의 인덱스를 더해서 answer[x][y] 인덱스를 변화시킴 












댓글

이 블로그의 인기 게시물

KT 에이블스쿨 : 대구광역시 공공데이터 활용 창업경진대회 준비

[KT 에이블스쿨 - IT 트랜드] 국내외 AI 관련 규제

KT 에이블스쿨 : 핀테크 아이디어 공모전