https://school.programmers.co.kr/learn/courses/30/lessons/43163?language=java

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr


문제

문제 설명
두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.

1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다.
2. words에 있는 단어로만 변환할 수 있습니다.
예를 들어 begin이 "hit", target가 "cog", words가 ["hot","dot","dog","lot","log","cog"]라면 "hit" -> "hot" -> "dot" -> "dog" -> "cog"와 같이 4단계를 거쳐 변환할 수 있습니다.

두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.

제한사항
각 단어는 알파벳 소문자로만 이루어져 있습니다.
각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
begin과 target은 같지 않습니다.
변환할 수 없는 경우에는 0를 return 합니다.
입출력 예
begin target words return
"hit" "cog" ["hot", "dot", "dog", "lot", "log", "cog"] 4
"hit" "cog" ["hot", "dot", "dog", "lot", "log"] 0


문제 해결을 위한 과정

 

이 문제는 한 글자만 다른 단어들을 체인처럼 엮어 목표 단어까지 도달하는 가장 짧은 경로를 찾는 문제입니다.

가중치가 없는 그래프의 최단 거리를 구할 때는 BFS(너비 우선 탐색)가 정석입니다.

 

특히, 단계를 정확하게 세기 위해 큐의 크기(q.size())만큼 끊어서 한 레벨씩 처리하는 레벨 단위 BFS 방식을 적용했습니다.

  1. 선제 예외 처리: target 단어가 words 배열 안에 없다면 애초에 변환이 불가능하므로 BFS를 시작하기도 전에 0을 리턴해 효율성을 챙깁니다.
  2. 레벨 단위 카운팅: while문이 돌 때마다 answer += 1을 통해 단계를 먼저 올려주고, 현재 큐에 들어있는 개수(len)만큼만 내부 for문을 돌려 같은 깊이(레벨)의 단어들을 한꺼번에 꺼냅니다.
  3. 조기 반환 (Early Return): 큐에서 꺼낸 단어(now)가 target과 일치하는 순간, 곧바로 값을 리턴하며 전체 탐색을 종료합니다.
  4. 다음 변환 단어 탐색: 아직 방문하지 않은 단어 중, 현재 단어와 딱 한 글자만 다른 단어를 찾아 큐에 추가하고 방문 처리합니다. (두 글자 이상 다르면 조기에 break하여 연산을 최적화합니다.)

소스코드
import java.util.*;

class Solution {
    public int solution(String begin, String target, String[] words) {
        int answer = 0;
        int n = words.length;
        
        boolean flag = false;
        for(int i = 0; i < n; i++) {
            if(target.equals(words[i])) {
                flag = true;
                break;
            }
        }
        if(!flag) {
            return 0;
        }
        
        boolean[] visited = new boolean[n];
        Queue<String> q = new LinkedList<>();
        q.offer(begin);
        
        while(!q.isEmpty()) {
            int len = q.size();
            answer += 1;
            for(int k = 0; k < len; k++) {
                String now = q.poll();
                if(now.equals(target)) {
                    return answer - 1;
                }   
                for(int i = 0; i < n; i++) {
                    int temp = 0;
                    if(visited[i])
                        continue;
                    for(int j = 0; j < now.length(); j++) {
                        if(temp >= 2)
                            break;
                        if(now.charAt(j) != words[i].charAt(j)) {
                            temp += 1;
                        }
                    }
                    if(temp == 1) {
                        q.offer(words[i]);
                        visited[i] = true;
                    }
                }   
            }
        }
        
        return 0;
    }
}

+ Recent posts