포스트

[Python] 프로그래머스 - 단어 변환

BFS를 활용한 단어 변환 문제 해결 원리와 deque, set 등 파이썬 자료구조 활용법

For the English version of this post, see here.
[Python] 프로그래머스 - 단어 변환

Programmers 단어 변환

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from collections import deque

def solution(begin, target, words):
    
    if target not in words:
        return 0
    else:
    
		    // 큐에 현재 단어와 변환 횟수를 저장
        queue = deque([(begin, 0)])
        visited = set([begin])
        
        while queue:
            current_word, step = queue.popleft()
            
            // 현재 단어가 target과 일치하면 변환 횟수를 return
            if current_word == target:
                return step
            
            // 다음 단계로 가능한 모든 단어를 queue에 넣음
            for word in words:
                if word not in visited:
                
		                // 알파벳이 1 다른지 확인
                    diff_cnt = sum(c1 != c2 for c1, c2 in zip(word, current_word))
                    if diff_cnt == 1:
                        visited.add(word)
                        queue.append((word, step + 1))
        
    return 0

풀이 과정

두 단어가 한 글자만 다르면 연결되어 있는 단어 그래프 문제이므로, queue를 이용하는 BFS를 사용하여 풀어야겠다고 생각했다.

그리고 위 문제와 같이 모든 이동 비용이 1인 최단 거리를 구하는 문제는 BFS가 잘 맞는다고 한다.

또한 DFS를 사용할 수도 있지만 그 경우에는 더 긴 경로가 있으면 그걸 먼저 찾을 수도 있기 때문에, target을 처음 만났을 때 최소를 보장하지 못하게 된다.

따라서 DFS 사용은 더 번거롭고 비효율적일 수 있다고 생각했다.

BFS에서는 ‘먼저 들어온 것을 먼저 꺼낸다.’와 같은 구조를 사용하기 때문에 양쪽에서 빠르게 넣고 뺄 수 있는 자료구조인 queue를 사용한다.

결과적으로 단어를 탐색하여 단어를 변경한 횟수를 반환해야되므로, 튜플을 사용하여 현재 단어와 변환 단계 수를 묶어서 queue에 저장하였다.

  • 튜플 (tuple): 여러 값을 하나로 묶는 자료구조

  • deque( [ (begin, 0) ] ) → 차례대로 deque 함수 호출, 리스트, 튜플을 사용하는 괄호를 의미한다.

visited에는 이미 방문한 단어를 저장하기 위해 set 집합을 사용하였다.

  • set 집합: 중복을 허용하지 않아서 방문 체크에 자주 사용

다음 변환 단어를 탐색하기 위해 튜플 언패킹을 했다.

  • 튜플 언패킹: 코드에서처럼 튜플로 저장한 두 값을 두 변수에 나눠 담음
    current_word, step = ("hit", 0)

두 문자열을 비교하여 알파벳이 1개만 다른지 확인하기 위해 zip()을 사용했다.

  • zip(): 각각 비교 문자열을 앞에서부터 하나씩 묶어줌
    zip(word, current_word)('h', 'h')

  • for c1, c2 in zip(word, current_word)
    → zip으로 묶인 글자 쌍을 하나씩 꺼내서 씀

  • diff_cnt = sum(c1 != c2 for c1, c2 in zip(word, current_word))
    → word와 current_word를 한 글자씩 비교해서 다른 글자의 개수를 세도록 함

    h == hFalse -> 0

    o != iTrue -> 1

최종적으로 코드에서 BFS는 0단계 단어 전부 확인 → 1단계 단어 전부 확인 → 2단계 단어 전부 확인 → … 순서로 탐색하여 짧은 거리부터 먼저 다 확인하게 된다.

따라서 처음 만난 step이 최소 변환 횟수가 될 수 있다.

댓글

궁금한 점, 피드백, 오류 제보를 남겨 주세요.