프로그래머스_게임 최단거리 (재풀이)

임정민·2023년 8월 3일
1

알고리즘 문제풀이

목록 보기
79/173
post-thumbnail

프로그래머스 BFS/DFS 문제입니다. 알고리즘 숙달을 위한 문제 반복풀이입니다. 실전에 대비하기 위해 60분 시간제한을 두고 풀었습니다.

문제

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

[나의 풀이1]

💥 효율성 테스트 실패 (25분 경과)

def solution(maps):

    x_len = len(maps)
    y_len = len(maps[0])

    # 우하좌상
    dx = [0,1,0,-1]
    dy = [1,0,-1,0]

    from collections import deque

    queue = deque([(0,0,1)])

    while queue:

        x,y,n = queue.pop()

        if x==x_len-1 and y==y_len-1:
            return n

        maps[x][y] = -1

        for i in range(4):
            
            newX = x+dx[i]
            newY = y+dy[i]

            if newX>=0 and newX<x_len and newY>=0 and newY<y_len:
            
                if maps[newX][newY] == 1:
                    queue.appendleft((newX,newY,n+1))

    if n != -1:
        return -1

2차원 맵 내의 목적지까지 최단거리를 구하는 문제입니다. 그래프 탐색의 대표적인 문제 유형이며 이전에 풀었던 문제로 큰 틀은 어렵지 않게 구현할 수 있었습니다.

하지만 위 코드로는 효율성 테스트에서 시간초과가 발생하였습니다. 이유로는 다음으로 이동 가능한 newX,newY좌표를 appendleft하는 즉시 -1로 초기화하지 않다보니 다른 케이스의 다음 좌표에서 그 다음 위치를 탐색할 때 -1인지 모르기 때문에 일단 appendleft 하는 경우가 생겨 시간이 더 오래 걸리게 됩었습니다.

[나의 풀이2]

⌛ 소요 시간 35분

def solution(maps):
	
    # col 크기
    x_len = len(maps)
    # row 크기
    y_len = len(maps[0])

    # 우하좌상
    dx = [0,1,0,-1]
    dy = [1,0,-1,0]

    from collections import deque
	
    # BFS 구현을 위한 queue 구조
    queue = deque([(0,0,1)])

    while queue:

        x,y,n = queue.pop()

        if x==x_len-1 and y==y_len-1:
            return n

        for i in range(4):
            
            newX = x+dx[i]
            newY = y+dy[i]

            if newX>=0 and newX<x_len and newY>=0 and newY<y_len:
            
                if maps[newX][newY] == 1:
                    maps[newX][newY] = -1
                    queue.appendleft((newX,newY,n+1))

    if n != -1:
        return -1

그리하여 방문한 좌표를 -1로 초기화 해주는 구문을 다음 이동 가능한 좌표로 발견한 즉시
maps[newX][newY] = -1 구문을 통해 초기화시켜 불필요한 확인을 줄일 수 있었습니다.

해당 문제는 DFS로 구현할 수도 있지만 DFS의 경우 모든 경로를 끝까지 탐색하기 때문에 BFS로 구현하는 것이 포인트였고

또, BFS 구조를 통해 queue 구조에 (x좌표, y좌표, 움직인 횟수(n))을 appendleft하여 구현하였습니다.

[다른 사람의 풀이1]

from collections import deque

def solution(maps):
    if len(maps) == 1 and len(maps[0]) == 1:
        return 1
    row_len = len(maps)
    vec_len = len(maps[0])
    dx = [0, 1, 0, -1]
    dy = [1, 0, -1, 0]

    # 맵 받기
    def bfs():
        queue = deque()
        queue.append((0, 0))
        
        while queue:
            row, vec = queue.popleft()
            if (row, vec) == (row_len - 1, vec_len - 1):
                return maps[row][vec]
            for (y, x) in zip(dy, dx):
                new_row = row + y
                new_vec = vec + x
                if new_row < 0 or new_row >= row_len or \
                    new_vec < 0 or new_vec >= vec_len or \
                    maps[new_row][new_vec] == 0 or \
                    (maps[new_row][new_vec] != 1 and 
                     maps[new_row][new_vec] <= maps[row][vec] + 1):
                    continue
                maps[new_row][new_vec] = maps[row][vec] + 1
                queue.append((new_row, new_vec))
        return -1

    return bfs()

저의 풀이와 유사한 구조이지만 최단거리를 구하는 문제이기 때문에 지나온 거리마다 +1 하여
목적지에 도달했을 때 해당 위치의 좌표롤 답을 도출하는 풀이입니다.

또한 이동할 수 있는지 여부를 판단할 때의 조건문 표현을 조금 다르게 하였습니다. 다음 x or y좌표가 맵을 벗어날때나 벽일 때, 다음위치가 이미 지나온 위치이기 때문에 현재 좌표값이 더 클 때의 케이스는 continue하여 appned 하지않는 방식입니다.

[다른 사람의 풀이2]

from collections import deque
def solution(maps):
    n = len(maps); m = len(maps[0])
    visited = [[False]*m for _ in range(n)]
    q = deque()
    q.append((0, 0))
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]
    visited[0][0]=True
    while q:
        y, x = q.popleft()
        for i in range(4):
            nx=x+dx[i]
            ny=y+dy[i]
            if 0<=nx<m and 0<=ny<n and maps[ny][nx] == 1:
                if not visited[ny][nx]:
                    visited[ny][nx] = True
                    q.append((ny, nx))
                    maps[ny][nx] = maps[y][x]+1
    if maps[n-1][m-1]==1:
        return -1
    else:
        return maps[n-1][m-1]

위 풀이는 BFS구조 , visited 리스트를 통해 방문 여부를 판별한 코드입니다. 또한 '다른 사람의 풀이1'과 같이 지나온 좌표에 +1씩하여 움직인 거리를 표기한 방식이었습니다.

감사합니다.

profile
https://github.com/min731

0개의 댓글