코딩테스트/문제

최단거리 - DFS/BFS

서히! 2025. 3. 13. 00:28
📌 DFS, BFS 사용예제
[ DFS ]
경로의 특징을 저장해둬야 하는 문제
ex. 각 정점에 숫자가 적혀있고 a부터 b까지 가는 경로를 구하는데 경로에 같은 숫자가 있으면 안 되는 조건 등
(BFS는 경로의 특징을 가지지 못함)
[ BFS ]
최단거리를 구하는 문제
ex. 문제미로 찾기

 

→ DFS는 모든 경로를 탐색해야되지만, BFS는 탐색 시 먼저 찾아지는 해답이 곧 최단거리이기 때문 (=최단 거리를 찾자마자 종료할 수 있음)

 

 

💡게임 맵 최단 거리(Lv.2)

 

📌 과정 :

현재 방문 좌표 / 다음 이동 좌표 (큐에 추가) / 큐 상태 (FIFO)

1 (0,0) (1,0) [(1,0)]
2 (1,0) (2,0) [(2,0)]
3 (2,0) (3,0) [(3,0)]
4 (3,0) (3,1) [(3,1)]
5 (3,1) (3,2) [(3,2)]
6 (3,2) (2,2) [(2,2)]
7 (2,2) (1,2), (2,3) [(1,2), (2,3)]
8 (1,2) (0,2) [(2,3), (0,2)]
9 (2,3) (2,4) [(0,2), (2,4)]
10 (0,2) (0,3) [(2,4), (0,3)]
11 (2,4) (3,4) [(0,3), (3,4)]
12 (0,3) (0,4) [(3,4), (0,4)]
13 (3,4) (4,4) (도착!) [(0,4), (4,4)]

 

📌 최단 경로:
(0,0) → (1,0) → (2,0) → (3,0) → (3,1) → (3,2) → (2,2) → (1,2) → (0,2) → (0,3) → (0,4) → (3,4) → (4,4) ✅

 

내 코드

from collections import deque

def solution(maps):
    queue = deque([(0, 0, 1)])
    row = len(maps)
    col = len(maps[0])
    visited = [[0] * col for _ in range(row)]
    
    while queue:
        x, y, depth = queue.popleft()
        
        if x == row-1 and y == col-1:
            return depth
        
        for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
            nx = x + dx
            ny = y + dy
            
            if 0 <= nx < row and 0 <= ny < col and maps[nx][ny] == 1 and visited[nx][ny] == 0:
                visited[nx][ny] = 1 # 방문 처리
                queue.append((nx, ny, depth+1))
    
    return -1

 

 

[ 풀면서 느낀 점 & 깨달은 점 ]

  • x, y 축이 너무 헷갈렸음
    원래 우리의 상식선에서는 y가 col, x가 row인데, 리스트는 row 순이기 때문에 x를 row, y를 col로 생각
  • 처음에 depth를 if 조건문에 해당될 때 +1을 하게 했는데 이렇게 할 경우 큐에 추가되는대로 depth가 증가하므로, 
    depth도 queue 원소로 같이 넣어야 됨!
  • TypeError: cannot unpack non-iterable int object
    →  deque([(0,0)]) 에서 [ ]안 괄호를 빼먹어서 난 에러 (deque 사용할 때 많이 발생하는 에러)
  • 조건문에서 & 대신 and 사용: &은 bit 단위로 비교를 하기 때문에 and를 써야 원하는 답이 나옴
  • visited 리스트 만들 때 리스트 컴프리핸션 사용하므로 row, col 순서 뒤바뀌지 않게 조심 (col 개수로 이루어진 0 리스트를 하나 만든 후, row 개만큼 반복)

 

💡단어 변환 (Lv.3)

이 문제도 begin 단어에서 target 단어까지의 최소 경로를 알아야되므로 BFS

 

내 코드

from collections import deque

def solution(begin, target, words):
    answer = 0
    queue = deque([(begin, 0)])
    visited = [0] * len(words)
    
    if target not in words:
        return 0
    
    while queue:
        current_word, step = queue.popleft()
        
        if current_word == target:
            return step
        
        for i, word in enumerate(words):
            count = 0
            for idx in range(len(word)):
                if word[idx] != current_word[idx]:
                    count += 1
            
            if count == 1 and visited[i] == 0:
                visited[i] = 1
                queue.append((word, step+1))
                print(queue, visited)

 

 

개선한 코드

  • 위 코드에서 문자열 안의 문자를 인덱스로 접근하는 불편함 → zip 함수 사용
  • 중복을 허용하지 않는 set() 사용
    List: 순서가 있으며, 데이터(값) 중복 허용
    Set: 순서가 없으며, 데이터(값) 중복을 허용하지 않음
    Map: Key&Value 구조, Key는 중복을 허용하지 않으며, Value(값)는 중복을 허용
    출처: https://hahahoho5915.tistory.com/35 
from collections import deque

def solution(begin, target, words):
    answer = 0
    queue = deque([(begin, 0)])
    visited = set()
    
    if target not in words:
        return 0
    
    while queue:
        current_word, step = queue.popleft()
        
        if current_word == target:
            return step
        
        for word in words:
            count = 0
            if word in visited:
                continue # 이미 방문했으면 건너뛰기
            
            for a, b in zip(current_word, word): # 문자 하나씩 비교
                if a != b:
                    count += 1
            
            if count == 1:
                visited.add(word)
                queue.append((word, step+1))

 

 

[ 풀면서 느낀 점 & 깨달은 점 ]

  • queue에 어떤 원소를 넣어야할지 헷갈림
    → 다음 원소로 어떻게 가야될지를 생각
    → 위 문제에서는 좌표를 이용해서 최단경로를 구하는 것이므로 좌표 + depth / 단어변환 문제에서는 다음 단어로 이동하고 그 단어의 자리를 바탕으로 가야되므로 단어와 몇 step을 거쳐야하는지 구하는 것이므로 단어 + step
  • 변수 초기화 지점 잘 생각하기 (depth, count)
  • BFS 흐름은 while queue → for 문에서 append!