카테고리 없음

[프로그래머스] 2021 카카오 인턴십 - 거리두기 확인하기

문제

https://programmers.co.kr/learn/courses/30/lessons/81302

 

코딩테스트 연습 - 거리두기 확인하기

[["POOOP", "OXXOX", "OPXPX", "OOXOX", "POXXP"], ["POOPX", "OXPXP", "PXXXO", "OXXXO", "OOOPP"], ["PXOPX", "OXOXP", "OXPOX", "OXXOP", "PXPOX"], ["OOOXX", "XOOOX", "OOOXX", "OXOOX", "OOOOO"], ["PXPXP", "XPXPX", "PXPXP", "XPXPX", "PXPXP"]] [1, 0, 1, 1, 1]

programmers.co.kr

 


풀이

 

처음엔 반복문을 돌며 기준 좌표 P를 찾았다.

기준 좌표에서 맨해튼 2 이하의 다른 P위치를 찾고 그것과 기준 좌표 사이가 O로 되어있는지, 로 되어있는지 확인하여

거리두기를 위반했는지 아닌지를 판단하려 했다.

def solution(places):
    answer = []
    for p in places:
        for i in range(len(p)):
            p[i] = list(p[i])
    
    print(places)
    
    coord = [(-2, 0), 
             (-1, -1), (-1, 0), (-1, 1), 
             (0, -2), (0, -1), (0, 1), (0, 2),
             (1, -1), (1, 0), (1, 1),
             (2, 0)]
    
    for p in places:
        for y in range(5):
            for x in range(5):
                if p[y][x] == 'P':
                    pCoord = []
                    #P의 맨해튼 거리 2 이하에 위치한 또다른 P의 좌표 저장
                    for c in coord:
                        if c[0]+y >= 0 and c[0]+y < 5 and c[1]+x >= 0 and c[1]+x < 5:
                            if p[y+c[0]][x+c[1]] == 'P':
                                pCoord.append(c)
                    #for c in pCoord:
                    #    for _y in range(c[0]):
                    #        print(_y)
                    
    for i in range(-1, -1, -1):
        print(i)
            
    
    return answer

그런데 풀면서 이건 아닌 것 같다는 예감이 들었다

너무 복잡해짐..

 

그래서 해설을 봤다. 참고로 코드는 제공되지 않고 아이디어만 적혀있다.

https://tech.kakao.com/2021/07/08/2021-%ec%b9%b4%ec%b9%b4%ec%98%a4-%ec%9d%b8%ed%84%b4%ec%8b%ad-for-tech-developers-%ec%bd%94%eb%94%a9-%ed%85%8c%ec%8a%a4%ed%8a%b8-%ed%95%b4%ec%84%a4/

 

2021 카카오 인턴십 for Tech developers 코딩 테스트 해설

2021년 카카오의 여름 인턴십의 첫 번째 관문인 코딩 테스트가 지난 2021년 5월 8일에 4시간에 걸쳐 진행되었습니다. 이번 인턴 코딩 테스트에서는 5문제가 출제되었습니다. 이전과 동일하게 쉬운

tech.kakao.com

 

앗 BFS/DFS 이었군

그래서 기준 좌표에서 상하좌우좌표에 P가 있다면 거리두기 위반, O가 있다면 스택에 좌표를 넣고 

그 좌표를 기준으로 P가 있는지 확인하였다.

다만 기준 좌표 P도 상하좌우중 한 곳에 있을 것이므로 P가 2개 이상이면 위반이라고 판단하였다.

def solution(places):
    answer = []
    
    for p in places:
        for i in range(len(p)):
            p[i] = list(p[i])
    
    coord = [(-1, 0), (0, -1), (0, 1), (1, 0)]
    
    
    for p in places:
        isFinished = False
        for y in range(5):
            for x in range(5):
                if p[y][x] == 'P': #기준 좌표
                    stack = []
                    for c in coord:
                        if c[0]+y >= 0 and c[0]+y < 5 and c[1]+x >= 0 and c[1]+x < 5:
                            if p[y+c[0]][x+c[1]] == 'P': #상하좌우에 P가 있을 경우
                                answer.append(0)
                                isFinished = True
                                break
                            if p[y+c[0]][x+c[1]] == 'O': #빈 테이블이 있을 경우 DFS 스택에 추가
                                stack.append((y+c[0],x+c[1]))
                    if isFinished:
                        break
                    for y1, x1 in stack:
                        pNum = 0
                        for c in coord:
                            if c[0]+y1 >= 0 and c[0]+y1 < 5 and c[1]+x1 >= 0 and c[1]+x1 < 5:
                                if p[y1+c[0]][x1+c[1]] == 'P': #기준 좌표 제외 P가 2개 이상일 경우 거리두기 위반
                                    pNum += 1
                                    if pNum > 1:
                                        answer.append(0)
                                        isFinished = True
                                        break
                        if isFinished:
                            break
                if isFinished:
                    break
            if isFinished:
                break
        if not isFinished:
            answer.append(1)
        
    return answer

 

어찌어찌 통과는 했는데 현타온다 ..

기존 코드를 재사용하면서 의식의 흐름대로 덧붙이다보니 더 더러워졌다.

깔끔하게 바꿔봐야겠다. 

 


다른 사람 코드

def check(place):
    for irow, row in enumerate(place):
        for icol, cell in enumerate(row):
            if cell != 'P':
                continue
            if irow != 4 and place[irow + 1][icol] == 'P':
                return 0
            if icol != 4 and place[irow][icol + 1] == 'P':
                return 0
            if irow < 3 and place[irow + 2][icol] == 'P' and place[irow + 1][icol] != 'X':
                return 0
            if icol < 3 and place[irow][icol + 2] == 'P' and place[irow][icol + 1] != 'X':
                return 0
            if irow != 4 and icol != 4 and place[irow + 1][icol + 1] == 'P' and (place[irow + 1][icol] != 'X' or place[irow][icol + 1] != 'X'):
                return 0
            if irow != 4 and icol != 0 and place[irow + 1][icol - 1] == 'P' and (place[irow + 1][icol] != 'X' or place[irow][icol - 1] != 'X'):
                return 0
    return 1

def solution(places):
    return [check(place) for place in places]

이사람은 DFS로 푼게 아니고

처음에 내가 풀었던대로 맨해튼 거리 2 이하의 다른 P와 그 사이값을 확인했다.

이게 더 효율적인 코드일 것 같긴 하다.

 

변수 네이밍이 괜찮은 것 같다.

irow, icol로 해서 row와 구분하여 행 열의 인덱스임이 드러난다. 또 cell이라고 네이밍해서 한 칸임이 잘 드러난 것 같다.

나는 매번 생각나는대로 네이밍하는데, 나중에 문제가 복잡해지면 헷갈려서 규칙을 정해두고 이름지으면 좋을 것 같다.

 

 

def solution(places):
    result = []
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]

    def f(i, j, cnt):
        nonlocal good
        if cnt >2 : return
        if -1<i<5 and -1<j<5:
            if graph[i][j] == 'X':
                return

            if cnt != 0 and graph[i][j] == 'P':
                good = 0
                return

            graph[i][j] = 'X'

            for w in range(4):
                ni = i+dx[w]
                nj = j+dy[w]
                f(ni, nj, cnt+1)

    for case in places:
        graph = [list(r) for r in case]
        good = 1
        for i in range(5):
            for j in range(5):
                if graph[i][j]=='P':
                    f(i,j,0)

        result.append(good)
    return result

이분은 재귀로 DFS를 구현하신 것 같다.

 

nonlocal 은 처음 봤다. (https://devbruce.github.io/python/py-13-global,nonlocal/)

함수로 빼지 않은 이유가 flag때문에 복잡해질까봐였는데, nonlocal 을 사용하면 한층 깔끔하게 짤 수 있을 것 같다.