이번 문제는 그래프에서 탐색을 기반으로 최단 경로를 찾는 문제입니다.
Given an n x n
binary matrix grid
, return the length of the shortest clear path in the matrix. If there is no clear path, return -1
.
A clear path in a binary matrix is a path from the top-left cell (i.e., (0, 0)
) to the bottom-right cell (i.e., (n - 1, n - 1)
) such that:
0
.The length of a clear path is the number of visited cells of this path.
Example 1:
Input: grid = [[0,1],[1,0]]
Output: 2
Example 2:
Input: grid = [[0,0,0],[1,1,0],[1,1,0]]
Output: 4
Example 3:
Input: grid = [[1,0,0],[1,1,0],[1,1,0]]
Output: -1
Constraints:
n == grid.length
n == grid[i].length
1 <= n <= 100
grid[i][j] is 0 or 1
n x n 이진 matrix인 grid가 주어졌을 때, 출발지에서 목적지까지 도착하는 가장 빠른 경로의 길이를 반환하는 문제입니다.
출발지는 왼쪽 위 (0,0) 위치이고 목적지는 오른쪽 아래 (n-1, n-1)위치입니다. grid에서 요소 값이 0인 cell만 지나갈 수 있으며, 8방향으로 이동이 가능합니다.
차근차근 문제 분석을 들어가보도록 하겠습니다(실제 제가 풀 때 생각한 흐름입니다).
해당 문제는 상하좌우, 모든 대각선 방향으로 이동이 가능합니다. 그리고 값이 0인 cell만 지나갈 수 있습니다. 그래프 순회 알고리즘을 통해 최단 경로를 구할 수 있을것 같습니다. 그래프 순회는 모든 정점을 탐색하기 때문에 이중에서 가장 짧은 길이를 선택하면 될 것입니다.
이전 스텝에서 그래프 순회를 사용하면 문제가 해결될 것이라 짐작을 했습니다. 이번에는 실제 예시를 통해 가능한 지 확인 해보겠습니다.
우선, BFS알고리즘을 먼저 생각해보았습니다.
위 그림처럼 BFS알고리즘을 사용하면 쉽게 최단 경로를 바로 구할 수 있습니다. 그렇다면 DFS알고리즘은 어떨까요?
DFS알고리즘으로도 구할 수 있지만, DFS알고리즘은 잘못된 곳으로 갈 경우 다시 돌아와서 진행해야 하기 때문에 최단 경로를 구하는 문제와는 적합하지 않을 수 있습니다 (물론 가능은 합니다.)
그럼, 이제 코드 설계를 진행해보겠습니다.
BFS알고리즘은 큐 자료구조를 활용합니다. 이번에는 큐 자료구조에 좌표값만 넣는것이 아니라 경로의 길이까지 넣습니다. 그 다음 8방향조건에 맞춰서 위치를 이동한 다음 그 위치가 1이 아니고, grid길이 내부에 있으면 이동하면 됩니다. 이동하면서 길이는 +1을 합니다. 방문하면 방문했다는 표시와 방문 위치 좌표를 큐 자료구조에 enqueue를 진행합니다.
from collections import deque
class Solution(object):
def shortestPathBinaryMatrix(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (1, 1), (1, -1), (-1, 1), (-1, -1)]
result = -1
m = len(grid)
n = len(grid[0])
if grid[0][0] != 0 or grid[m-1][n-1] != 0:
return result
queue = deque()
queue.append((0,0,1))
visited = [[False] * n for _ in range(m)]
visited[0][0] = True
while queue:
cur_x, cur_y,cur_d = queue.popleft()
if cur_x == m - 1 and cur_y == n - 1:
result = cur_d
break
for dx, dy in directions:
next_x = cur_x + dx
next_y = cur_y + dy
if 0 <= next_x and next_x < m and 0 <= next_y and next_y < n:
if grid[next_x][next_y] == 0 and not visited[next_x][next_y]:
queue.append((next_x,next_y,cur_d+1))
visited[next_x][next_y] = True
return result
코드 설명:
directions
리스트에 저장합니다:directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (1, 1), (1, -1), (-1, 1), (-1, -1)]
grid[0][0]
또는 끝점 grid[m-1][n-1]
이 1
인 경우, 경로가 없으므로 1
을 반환합니다:if grid[0][0] != 0 or grid[m-1][n-1] != 0:
return -1
queue
를 초기화하고, 시작점 (0, 0)
과 초기 경로 길이 1
을 큐에 추가합니다:
queue = deque()
queue.append((0, 0, 1))
visited
배열을 생성하고, 시작점을 방문 처리합니다:
visited = [[False] * n for _ in range(m)]
visited[0][0] = True
(m-1, n-1)
라면 경로 길이를 반환합니다:
if cur_x == m - 1 and cur_y == n - 1:
result = cur_d
break
for dx, dy in directions:
next_x = cur_x + dx
next_y = cur_y + dy
if 0 <= next_x < m and 0 <= next_y < n:
if grid[next_x][next_y] == 0 and not visited[next_x][next_y]:
queue.append((next_x, next_y, cur_d + 1))
visited[next_x][next_y] = True
1
을 반환합니다.시간 복잡도:
O($n^2$)
입니다.O(1)
이며, 최대 $n^2$
개의 셀이 처리되므로 큐 연산의 복잡도는 $O(n^2)$
입니다.$O(n^2)$
입니다.결과:
https://leetcode.com/problems/shortest-path-in-binary-matrix/submissions/1455837687
이번 문제는 그래프 탐색 알고리즘 중 BFS의 강력함을 보여주는 전형적인 사례입니다. 최단 경로를 찾기 위해 DFS보다 BFS가 더 적합하다는 것을 알 수 있었습니다. 8방향으로의 이동 조건과 경로의 유효성을 확인하는 부분이 문제 풀이의 핵심이었습니다.
추가적으로, BFS를 활용한 문제 해결 방식은 다른 그래프 문제에서도 유사하게 응용될 수 있습니다. 특히, 격자형 그래프에서 최단 경로를 찾는 문제를 연습할 때 유용한 예제였습니다.
DFS, BFS 문제들은 정말 빈출 유형의 문제입니다. 많은 반복만이 살 길입니다!! 🚀
전체 코드는 다음 링크에서 확인할 수 있습니다.
읽어주셔서 감사합니다.
매일 발전하는 개발자가 되기를,,,!💪