-
[Algorithm: DFS] 프로그래머스 <단어 변환>Algorithms 2026. 5. 2. 15:43DFS 백트래킹 Java Programmers Lv.3
문제
https://school.programmers.co.kr/learn/courses/30/lessons/43163
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 설명
단어
begin에서target으로 변환하는 최소 단계를 구하는 문제다. 단, 한 번에 한 글자만 바꿀 수 있고, 변환 결과는 반드시words목록에 있는 단어여야 한다.begin target words return hit cog ["hot","dot","dog","lot","log","cog"] 4 hit cog ["hot","dot","dog","lot","log"] 0 hit → hot → dot → dog → cog
한 글자씩 바꾸면서 4단계 만에 도달. 답은 4.문제 핵심 파악
이 문제는 두 가지 조건을 동시에 만족해야 한다.
조건 1. 현재 단어와 딱 한 글자만 다른 단어로만 이동 가능
조건 2. 이동할 단어는 반드시words목록에 있어야 함가능한 변환 경로가 여러 개일 수 있으므로 DFS로 모든 경로를 탐색하고, 그 중 가장 적은 단계로 도달하는 값을 찾는다.
target이 words에 없으면 즉시 0을 반환한다.
어떤 경로로도 target에 도달할 수 없기 때문에 탐색 전에 먼저 확인한다.핵심 아이디어: 글자 차이 count
현재 단어에서 이동 가능한 단어를 찾으려면 글자가 딱 1개만 다른 단어를 찾으면 된다. 두 단어를 같은 인덱스끼리 비교해서 다른 글자의 개수를 세는 방식으로 구현한다.
글자 차이 비교 — begin="hot"
begin h o tdot d o t diff=1 이동 가능dog d o g diff=2 이동 불가lot l o t diff=1 이동 가능cog c o g diff=2 이동 불가int diff = 0; for (int j = 0; j < words[0].length(); j++) { if (begin.charAt(j) != words[i].charAt(j)) { diff++; } } if (!visited[i] && diff == 1) { // 한 글자만 다르고 미방문 // 이동 가능 }
DFS 탐색 흐름 시각화
예시 1
begin="hit", target="cog", words=["hot","dot","dog","lot","log","cog"]을 단계별로 추적해보자.dfs("hit", count=0)
hithit와 1글자 차이: hot(diff=1) ✓, dot(diff=2) ✗, 나머지 모두 diff≥2 ✗
dfs("hot", count=1) — hit → hot
hit → hot count=1hot와 1글자 차이: dot(diff=1) ✓, lot(diff=1) ✓
words 순서상 dot을 먼저 선택
dfs("dot", count=2) — hot → dot
hit → hot → dot count=2dot와 1글자 차이: dog(diff=1) ✓, lot(diff=1) ✓
words 순서상 dog를 먼저 선택
dfs("dog", count=3) — dot → dog
hit → hot → dot → dog count=3dog와 1글자 차이: cog(diff=1) ✓, log(diff=1) ✓
words 순서상 cog를 먼저 선택
dfs("cog", count=4) — dog → cog ✓
hit → hot → dot → dog → cog count=4begin.equals(target) → answer = 4 저장
answer = 4DFS 호출 스택 전체 흐름
백트래킹이 어떻게 이루어지는지 콜스택 관점으로 정리하면 이렇다.
dfs("hit", 0) hot diff=1 → dfs("hot", 1) dot diff=1 → dfs("dot", 2) dog diff=1
→ dfs("dog", 3) cog diff=1 → visited[cog]=true
→ dfs("cog", 4) begin == target → answer = 4
dfs("cog") 종료 → visited[cog]=false (백트래킹)
log diff=1 → visited[log]=true → dfs("log", 4) cog diff=1이지만
visited[cog]=false → dfs("cog", 5) begin == target → answer = 5 ← 더 큰 값으로 덮어써짐!
dfs("log") 종료 → 백트래킹 dfs("dog") 종료 → 백트래킹 lot diff=1 → dfs("lot", 2) ...계속 탐색실은 덮어쓰기가 발생한다!
dog → cog(count=4)로 answer=4를 저장한 뒤 백트래킹하면visited[cog]=false로 되돌아간다.
그러면 이후 dog → log → cog(count=5) 경로에서 cog를 다시 방문할 수 있게 되어answer=5로 덮어써진다.
visited 배열은 cog가 현재 경로에서 사용 중인지를 추적할 뿐, 전체 탐색에서 이미 방문했는지를 막지 않는다.올바른 종료 조건:
if (begin.equals(target))내부에서if (answer == 0 || count < answer) answer = count;
으로 수정해야 더 긴 경로가 나중에 도달해도 최솟값이 유지된다.백트래킹의 역할
DFS로 한 경로를 끝까지 탐색한 뒤, 되돌아와 다른 경로를 시도한다.
visited배열을 활용해 현재 경로에서 이미 사용한 단어를 다시 쓰지 않도록 막는다.visited[i] = true; // 단어 사용 dfs(words[i], target, words, count + 1); // 깊이 탐색 visited[i] = false; // 백트래킹: 단어 반납visited[i] = false로 되돌리기 때문에
다른 경로에서 같은 단어를 다시 사용할 수 있다.
예를 들어 hit→hot→dot 경로와 hit→hot→lot 경로가 모두 hot을 방문하지만,
각각 독립적인 탐색에서 hot을 재사용할 수 있다.
최종 코드
import java.util.*; class Solution { boolean[] visited; int answer = 0; public int solution(String begin, String target, String[] words) { visited = new boolean[words.length]; // target이 words에 없으면 변환 불가 ArrayList<String> wordList = new ArrayList<>(Arrays.asList(words)); if (!wordList.contains(target)) return 0; dfs(begin, target, words, 0); return answer; } void dfs(String begin, String target, String[] words, int count) { if (begin.equals(target)) { // 백트래킹으로 더 긴 경로가 나중에 도달할 수 있으므로 최솟값 갱신 if (answer == 0 || count < answer) answer = count; return; } for (int i = 0; i < words.length; i++) { int diff = 0; for (int j = 0; j < words[0].length(); j++) { if (begin.charAt(j) != words[i].charAt(j)) diff++; } if (!visited[i] && diff == 1) { visited[i] = true; dfs(words[i], target, words, count + 1); visited[i] = false; // 백트래킹 } } } }
정리
사전 확인target이 words에 없으면 즉시 0 반환. 불필요한 탐색을 막는 첫 번째 방어선.글자 차이 계산두 단어를 인덱스별로 비교해 diff를 센다. diff==1인 단어만 이동 대상.백트래킹visited=true로 단어를 선택, DFS 완료 후 visited=false로 반납. 모든 경로를 독립적으로 탐색.최솟값 갱신target 도달 시 answer==0이거나 count가 더 작을 때만 저장. 더 긴 경로로 덮어쓰기 방지.이 문제의 본질은 그래프 최단 경로 탐색이다.
단어를 노드, 1글자 차이를 엣지로 보면 BFS로도 풀 수 있다.
DFS로 풀 때는 모든 경로를 탐색하면서 최솟값을 갱신하는 방식이므로,
answer를 마지막이 아닌 최솟값으로 갱신하는 것이 핵심 포인트다.* 이 포스팅은 Claude AI의 도움을 받아서 작성되었습니다.
'Algorithms' 카테고리의 다른 글
[Algorithm: 큐] 프로그래머스 <프로세스> (0) 2026.05.17 [Algorithm: DFS] 프로그래머스 <퍼즐 조각 채우기> (0) 2026.05.13 [Algorithm: DFS] 프로그래머스 <여행경로> (0) 2026.05.01 [Algorithm: DFS] 프로그래머스 <네트워크> (0) 2026.05.01 [Algorithm: 그리디] 프로그래머스 <조이스틱> (0) 2026.04.28